netfiler iptable初始化
static int __init iptable_filter_init(void)
{
int ret;
/*
在NF_INET_LOCAL_IN,NF_INET_FORWARD,NF_INET_LOCAL_OUT三个点上注册netfilter hook函数iptable_filter_hook
*/
filter_ops = xt_hook_ops_alloc(&packet_filter, iptable_filter_hook);
if (IS_ERR(filter_ops))
return PTR_ERR(filter_ops);
ret = register_pernet_subsys(&iptable_filter_net_ops);
if (ret < 0)
kfree(filter_ops);
return ret;
}
static int __net_init iptable_filter_table_init(struct net *net)
{
struct ipt_replace *repl;
int err;
if (net->ipv4.iptable_filter)
return 0;
repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
/* Entry 1 is the FORWARD hook */
((struct ipt_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ipt_register_table(net, &packet_filter, repl, filter_ops,
&net->ipv4.iptable_filter);
kfree(repl);
return err;
}
ipt_register_table会调用nf_register_net_hooks在上面说的三个注册点上注册hook函数iptable_filter_hook。
生成的table存在net->ipv4.iptable_filter里面。
static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
if (state->hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
}
conntract
注册hooks
nf_conntrack_l3proto_ipv4_init() ->
ret = nf_register_hooks(ipv4_conntrack_ops,
ARRAY_SIZE(ipv4_conntrack_ops));
static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
{
.hook = ipv4_conntrack_in,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK,
},
{
.hook = ipv4_conntrack_local,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK,
},
{
.hook = ipv4_helper,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
},
{
.hook = ipv4_confirm,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
},
{
.hook = ipv4_helper,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
},
{
.hook = ipv4_confirm,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
},
};
注册L4 proto
nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp4);
rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto);
nf_ct_protosl4proto被初始化成一个每个元素都指向nf_conntrack_l4proto_generic的二维数组。注册的时候把nf_ct_protosl4proto替换成相应的proto
通过函数__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
可以取回相应的proto
注册L3 proto
ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv4);
建立连接
nf_conntrack_in() -> resolve_normal_ct() -> init_conntrack()
建立一个新的conntrack,这个时候skb->nfctinfo=IP_CT_NEW
。在这个过程中,上面注册的l4proto里面的函数就会被调用,比如说tcp_error, tcp_new, tcp_packet,来决定这个conntrack的状态。
tcp SYNC收到后,ct->proto.tcp.state = TCP_CONNTRACK_SYN_SENT