cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
阅读:4690回复:5

2.6.26内核连线跟踪简单分析

楼主#
更多 发布于:2009-01-16 19:03
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);
}
走走看看开源好 Solaris vs Linux
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
沙发#
发布于: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;
}
走走看看开源好 Solaris vs Linux
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
板凳#
发布于: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为例。
走走看看开源好 Solaris vs Linux
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
地板#
发布于: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协议中,会更新连接状态。
走走看看开源好 Solaris vs Linux
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
地下室#
发布于: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); /* 插入表中 */

。。。

/* 超时时间 */
}


}
走走看看开源好 Solaris vs Linux
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
5楼#
发布于:2009-01-17 19:31
不错阿:)
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
游客

返回顶部