一、
IP报文的接收到hook函数的调用
1.1
ip_input.c
ip_rcv()函数
以接收到的报文为例,类似的还有ip_forward(ip_forward.c)和ip_output(ip_output.c)
int ip_rcv(struct sk_buff *skb, struct net_device
*dev, struct packet_type *pt, struct net_device *orig_dev)
{
struct iphdr *iph;
//定义一个ip报文的数据报头
u32
len;
if
(skb->pkt_type == PACKET_OTHERHOST)
goto drop; //数据包不是发给我们的
IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); //收到数据包统计量加1
if
((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
{
IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
goto out;
}
if
(!pskb_may_pull(skb, sizeof(struct iphdr)))
goto inhdr_error; //对数据报的头长度进行检查,
iph =
skb->nh.iph; //取得数据报的头部位置
if (iph->ihl < 5 ||
iph->version != 4) //版本号或者头长度不对,goto
inhdr_error; //头长度是以4字节为单位的,所以5表示的是20字节
if (!pskb_may_pull(skb,
iph->ihl*4))
goto
inhdr_error;
if (unlikely(ip_fast_csum((u8
*)iph, iph->ihl)))
goto inhdr_error; //检查报文的检验和字段
len =
ntohs(iph->tot_len);
if (skb->len < len || len <
(iph->ihl*4))
goto
inhdr_error; //整个报文长度不可能比报头长度小
if (pskb_trim_rcsum(skb,
len))
{ //对数据报进行裁减,这样可以分片发送过来的数据报不会有重复数据IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
goto drop;
}
return
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish); //通过回调函数调用ip_rcv_finish
inhdr_error:
IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
drop:
kfree_skb(skb); //丢掉数据报out:
return NET_RX_DROP;
}
1.2
include/linux/netfilter.h
NF_HOOK宏
#ifdef
CONFIG_NETFILTER_DEBUG
#define NF_HOOK(pf, hook, skb, indev, outdev,
okfn)
\
nf_hook_slow((pf),
(hook), (skb), (indev), (outdev), (okfn), INT_MIN)
#define NF_HOOK_THRESH nf_hook_slow
#else
#define NF_HOOK(pf, hook, skb, indev, outdev,
okfn)
\
(list_empty(&nf_hooks[(pf)][(hook)])
\
?
(okfn)(skb)
\
: nf_hook_slow((pf), (hook), (skb), (indev), (outdev),
(okfn), INT_MIN))
#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn,
thresh)
\
(list_empty(&nf_hooks[(pf)][(hook)])
\
?
(okfn)(skb)
\
:
nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn),
(thresh)))
#endif
1.3
net/core/netfilter.c
nf_kook_slow()函数
int
nf_hook_slow(int pf, unsigned int hook, struct sk_buff
**pskb,
struct
net_device *indev,
struct
net_device *outdev,
int
(*okfn)(struct sk_buff *),
int
hook_thresh)
{
struct list_head *elem;
unsigned int verdict;
int ret = 0;
rcu_read_lock();
elem = &nf_hooks[pf][hook];
next_hook:
verdict =
nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
outdev,
&elem, okfn, hook_thresh);
if (verdict == NF_ACCEPT || verdict == NF_STOP) {
ret =
1; goto
unlock;
} else if (verdict ==
NF_DROP) {
kfree_skb(*pskb); ret = -EPERM;
} else if (verdict ==
NF_QUEUE) {
NFDEBUG("nf_hook: Verdict =
QUEUE.\n");
if (!nf_queue(*pskb, elem, pf, hook, indev,
outdev, okfn))
goto
next_hook;
}
unlock:
rcu_read_unlock();
return ret;
}
1.4
net/core/netfilter.c nf_iterate()函数
static unsigned int
nf_iterate(struct list_head *head,
struct sk_buff **skb,
int hook,
const struct net_device *indev,
const struct net_device *outdev,
struct list_head **i,
int (*okfn)(struct sk_buff *),
int hook_thresh)
{
list_for_each_continue_rcu(*i, head) {
struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
if (hook_thresh > elem->priority)
continue;
switch (elem->hook(hook, skb, indev,
outdev, okfn)) {
case NF_QUEUE:
return NF_QUEUE;
case NF_STOLEN:
return NF_STOLEN;
case NF_DROP:
return NF_DROP;
case NF_REPEAT:
*i = (*i)->prev;
break;
}
}
return NF_ACCEPT;
}
二、ipt_table数据结构和表的初始化
2.1
include/linux/netfilter_ipv4/ip_tables.h struct ipt_table
表结构struct ipt_table{
struct list_head list;
char name[IPT_TABLE_MAXNAMELEN];
struct ipt_replace *table;
unsigned int valid_hooks;
rwlock_t lock;
struct ipt_table_info
*private;
struct module *me;
};
2.2 struct
ipt_table_info是实际描述表的数据结构
ip_tables.c
struct ipt_table_info
{
unsigned int size;
unsigned int number;
unsigned int initial_entries;
unsigned int hook_entry[NF_IP_NUMHOOKS];
unsigned int underflow[NF_IP_NUMHOOKS];
char entries[0] ____cacheline_aligned;
};
2.3
include/linux/netfilter_ipv4 规则用struct ipt_entry结构表示,包含匹配用的IP头部分、一个Target和0个或多个Match。由于Match数不定,所以一条规则实际的占用空间是可变的。结构定义如下
struct ipt_entry
{
struct ipt_ip ip;
unsigned int nfcache;
u_int16_t target_offset;
u_int16_t next_offset;
unsigned int comefrom;
struct ipt_counters counters;
unsigned char elems[0];
}
2.4 iptables的初始化init(void) ,以filter表为例
iptable_filter.c
static int __init
init(void)
{
int ret;
if (forward < 0 || forward > NF_MAX_VERDICT) {
printk("iptables forward must be 0 or 1\n");
return -EINVAL;
}
initial_table.entries[1].target.verdict = -forward - 1;
ret = ipt_register_table(&packet_filter);
//注册filter表
if (ret < 0)
return ret;
ret = nf_register_hook(&ipt_ops[0]);
//注册三个HOOK
if (ret < 0)
goto cleanup_table;
ret = nf_register_hook(&ipt_ops[1]);
if (ret < 0)
goto cleanup_hook0;
ret = nf_register_hook(&ipt_ops[2]);
if (ret < 0)
goto cleanup_hook1;
return ret;
cleanup_hook1:
nf_unregister_hook(&ipt_ops[1]);
cleanup_hook0:
nf_unregister_hook(&ipt_ops[0]);
cleanup_table:
ipt_unregister_table(&packet_filter);
return ret;
}
static struct
ipt_table packet_filter = {
.name
= "filter",
.table
= &initial_table.repl,
.valid_hooks =
FILTER_VALID_HOOKS,
.lock
= RW_LOCK_UNLOCKED,
.me
= THIS_MODULE
};
struct
ipt_replace
{
char name[IPT_TABLE_MAXNAMELEN];
unsigned int valid_hooks;
unsigned int num_entries;
unsigned int size;
unsigned int hook_entry[NF_IP_NUMHOOKS];
unsigned int underflow[NF_IP_NUMHOOKS];
unsigned int num_counters;
struct ipt_counters __user *counters;
struct ipt_entry entries[0];
};
static
struct
{
struct ipt_replace
repl;
struct ipt_standard entries[3];
struct ipt_error term;
} initial_table
__initdata
= { { "filter", FILTER_VALID_HOOKS, 4,
sizeof(struct ipt_standard) * 3 + sizeof(struct
ipt_error),
{ [NF_IP_LOCAL_IN] = 0,
[NF_IP_FORWARD] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
{ [NF_IP_LOCAL_IN] = 0,
[NF_IP_FORWARD] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
0, NULL, { } },
{
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0
},
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { }
},
-NF_ACCEPT - 1 } },
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0
},
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { }
},
-NF_ACCEPT - 1 } },
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0
},
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { }
},
-NF_ACCEPT - 1 } }
},
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0
},
0,
sizeof(struct ipt_entry),
sizeof(struct ipt_error),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_error_target)),
IPT_ERROR_TARGET } },
{ }
},
"ERROR"
}
}
};