netfiler学习

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

你可能感兴趣的:(程序员)