Netfilter 之 iptable_mangle

初始化

iptable_mangle_table_init函数通过调用ipt_register_table完成mangle表注册和钩子函数注册的功能;该流程与iptable_filter的函数调用的函数一致,此处不再重复分析,详情请移步<iptable_filter分析>;

 1 static int __net_init iptable_mangle_table_init(struct net *net)
 2 {
 3     struct ipt_replace *repl;
 4     int ret;
 5 
 6     /* 已经初始化 */
 7     if (net->ipv4.iptable_mangle)
 8         return 0;
 9 
10     /* 分配初始化用于下面注册的结构 */
11     repl = ipt_alloc_initial_table(&packet_mangler);
12     if (repl == NULL)
13         return -ENOMEM;
14     /* 注册表和钩子函数 */
15     ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
16                  &net->ipv4.iptable_mangle);
17     kfree(repl);
18     return ret;
19 }
钩子函数

从下面的钩子函数可以看到其分布于全部5个钩子点;

1 #define MANGLE_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
2                 (1 << NF_INET_LOCAL_IN) | \
3                 (1 << NF_INET_FORWARD) | \
4                 (1 << NF_INET_LOCAL_OUT) | \
5                 (1 << NF_INET_POST_ROUTING))
1 static const struct xt_table packet_mangler = {
2     .name        = "mangle",
3     .valid_hooks    = MANGLE_VALID_HOOKS,
4     .me        = THIS_MODULE,
5     .af        = NFPROTO_IPV4,
6     .priority    = NF_IP_PRI_MANGLE,
7     .table_init    = iptable_mangle_table_init,
8 };

iptable_mangle_hook为mangle钩子函数,如果当前是处于LOCAL_OUT钩子点,则需要调用ip_mangle_out函数,其他店则调用ipt_do_table进行规则匹配;ipt_do_table函数此处不再重复分析,详情请移步<iptable_filter分析>;

 1 static unsigned int
 2 iptable_mangle_hook(void *priv,
 3              struct sk_buff *skb,
 4              const struct nf_hook_state *state)
 5 {
 6     /* LOCAL_OUT钩子点,调用mangle_out */
 7     if (state->hook == NF_INET_LOCAL_OUT)
 8         return ipt_mangle_out(skb, state);
 9     /* 规则匹配 */
10     return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
11 }

ipt_mangle_out首先保存ip头部的一些信息,然后调用ipt_do_table进行规则匹配,规则之后检查ip头中的保存字段是否发生变化,如果发生变化,则需要重新查路由;

 1 static unsigned int
 2 ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
 3 {
 4     unsigned int ret;
 5     const struct iphdr *iph;
 6     u_int8_t tos;
 7     __be32 saddr, daddr;
 8     u_int32_t mark;
 9     int err;
10 
11     /* root is playing with raw sockets. */
12     /* 原始套接字 */
13     if (skb->len < sizeof(struct iphdr) ||
14         ip_hdrlen(skb) < sizeof(struct iphdr))
15         return NF_ACCEPT;
16 
17     /* Save things which could affect route */
18     
19     mark = skb->mark;
20     iph = ip_hdr(skb);
21     saddr = iph->saddr;
22     daddr = iph->daddr;
23     tos = iph->tos;
24 
25     /* 进行规则匹配 */
26     ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
27     /* Reroute for ANY change. */
28     /* 经过规则后 */
29     if (ret != NF_DROP && ret != NF_STOLEN) {
30         iph = ip_hdr(skb);
31 
32         /* 判断ip头中的字段是否有改变 */
33         if (iph->saddr != saddr ||
34             iph->daddr != daddr ||
35             skb->mark != mark ||
36             iph->tos != tos) {
37             /* 重新查路由 */
38             err = ip_route_me_harder(state->net, skb, RTN_UNSPEC);
39             if (err < 0)
40                 ret = NF_DROP_ERR(err);
41         }
42     }
43 
44     return ret;
45 }

猜你喜欢

转载自www.cnblogs.com/wanpengcoder/p/11755756.html