阅读:4690回复:5
2.6.26内核连线跟踪简单分析
2.6.26内核连线跟踪简单分析
author: cyliu 1 nf_conntrack_standalone_init 初始化 static int __init nf_conntrack_standalone_init(void) { int ret; ret = nf_conntrack_init(); /* init 0 */ /* 初始化conn全局表 */ goto out; ret = nf_conntrack_standalone_init_proc(); /* init 1 */ if (ret < 0) goto out_proc; ret = nf_conntrack_standalone_init_sysctl(); /* init 2 */ if (ret < 0) goto out_sysctl; return 0; ... return ret; } 2 nf_conntrack_init 初始化全局连表变量 int __init nf_conntrack_init(void) { ... nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, &nf_conntrack_vmalloc); 。。。 nf_conntrack_cachep = kmem_cache_create("nf_conntrack", sizeof(struct nf_conn), 0, 0, NULL); 。。。 ret = nf_conntrack_proto_init(); 。。。 } 3 nf_conntrack_l3proto_ipv4_init 初始化跟踪协议 static int __init nf_conntrack_l3proto_ipv4_init(void) { int ret = 0; need_conntrack(); ret = nf_register_sockopt(&so_getorigdst); /* sock 相关 */ if (ret < 0) { printk(KERN_ERR "Unable to register netfilter socket option\n"); return ret; } /* 依次注册tcp,udp,icmp */ ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4); 。。。 ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4); if (ret < 0) { printk("nf_conntrack_ipv4: can't register ipv4\n"); goto cleanup_icmp; } ret = nf_register_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));/***重要***/ ... return ret; ... return ret; } static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = { { .hook = ipv4_conntrack_defrag, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_CONNTRACK_DEFRAG, }, { .hook = ipv4_conntrack_in, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_CONNTRACK, }, { .hook = ipv4_conntrack_defrag, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_CONNTRACK_DEFRAG, }, { .hook = ipv4_conntrack_local, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_CONNTRACK, }, { .hook = ipv4_confirm, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }, { .hook = ipv4_confirm, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }, }; 4 PRE_ROUTING点 创建联线数据结构 static unsigned int ipv4_conntrack_in(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { return nf_conntrack_in(PF_INET, hooknum, skb); } |
|
|
沙发#
发布于:2009-01-16 19:10
unsigned int
nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb) { ... struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; unsigned int dataoff; u_int8_t protonum; int set_reply = 0; int ret; /* Previously seen (loopback or untracked)? Ignore. */ if (skb->nfct) {/* 已经存在 */ NF_CT_STAT_INC_ATOMIC(ignore); return NF_ACCEPT; } /* rcu_read_lock()ed by nf_hook_slow */ l3proto = __nf_ct_l3proto_find((u_int16_t)pf); /* 找3层协议 */ ret = l3proto->get_l4proto(skb, skb_network_offset(skb), &dataoff, &protonum); if (ret <= 0) { pr_debug("not prepared to track yet or error occured\n"); NF_CT_STAT_INC_ATOMIC(error); NF_CT_STAT_INC_ATOMIC(invalid); return -ret; } l4proto = __nf_ct_l4proto_find((u_int16_t)pf, protonum); /* 找4层协议 */ ... ct = resolve_normal_ct(skb, dataoff, pf, protonum, l3proto, l4proto, &set_reply, &ctinfo); ... ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum); if (ret < 0) { /* Invalid: inverse of the return code tells * the netfilter core what to do */ pr_debug("nf_conntrack_in: Can't track with proto module\n"); nf_conntrack_put(skb->nfct); skb->nfct = NULL; NF_CT_STAT_INC_ATOMIC(invalid); return -ret; } ... return ret; } |
|
|
板凳#
发布于:2009-01-16 19:22
static inline struct nf_conn *
resolve_normal_ct(struct sk_buff *skb, unsigned int dataoff, u_int16_t l3num, u_int8_t protonum, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, int *set_reply, enum ip_conntrack_info *ctinfo) { struct nf_conntrack_tuple tuple; /* 5元组 */ struct nf_conntrack_tuple_hash *h; /* 5元组 hash表*/ struct nf_conn *ct; if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, protonum, &tuple, l3proto, l4proto)) { /* 计算5元组 ,重要是调用前面注册的3和4层协议的pkt_to_tuple函数*/ pr_debug("resolve_normal_ct: Can't get tuple\n"); return NULL; } /*得到5元组 */ /* look for tuple match */ h = nf_conntrack_find_get(&tuple); if (!h) { /* 未找到,创建新的连线信息 */ h = init_conntrack(&tuple, l3proto, l4proto, skb, dataoff); if (!h) return NULL; if (IS_ERR(h)) return (void *)h; } ct = nf_ct_tuplehash_to_ctrack(h); /* 获取连线conn指针 */ /* It exists; we have (non-exclusive) reference. */ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY; /* Please set reply bit if this packet OK */ *set_reply = 1; } else { /* Once we've had two way comms, always ESTABLISHED. */ /* 设置联线状态 */ .... skb->nfct = &ct->ct_general; skb->nfctinfo = *ctinfo; return ct; } 下一步调用四层协议的packet。这里以gre为例。 |
|
|
地板#
发布于:2009-01-16 19:32
static int gre_packet(struct nf_conn *ct,
const struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, int pf, unsigned int hooknum) { /* 除了更新时间,基本没有做什么 */ 。。。 return NF_ACCEPT; } 但是在tcp协议中,会更新连接状态。 |
|
|
地下室#
发布于:2009-01-16 19:40
static unsigned int ipv4_confirm(unsigned int hooknum,
struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; unsigned int ret; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) goto out; help = nfct_help(ct); if (!help) goto out; /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) goto out; ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); if (ret != NF_ACCEPT) return ret; if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { typeof(nf_nat_seq_adjust_hook) seq_adjust; seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) return NF_DROP; } out: /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(skb); /* 确认 */ 主要是__nf_conntrack_confirm函数 int __nf_conntrack_confirm(struct sk_buff *skb) { 。。。 hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, &h->tuple)) /* 已经存在,推出 */ goto out; hlist_for_each_entry(h, n, &nf_conntrack_hash[repl_hash], hnode) if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, &h->tuple)) /* 已经存在,推出 */ goto out; /* Remove from unconfirmed list */ hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); __nf_conntrack_hash_insert(ct, hash, repl_hash); /* 插入表中 */ 。。。 /* 超时时间 */ } } |
|
|
5楼#
发布于:2009-01-17 19:31
不错阿:)
|
|
|