- 论坛徽章:
- 0
|
4.2. ip_conntrack_in()
函数ip_conntrack_in()被挂载在钩子点NF_IP_PRE_ROUTING,同时该函数也被挂载在钩子点NF_IP_LOCAL_OUT的函数ip_conntrack_local()调用,连接跟踪模块在这两个钩子点挂载的函数对数据包的处理区别仅在于对分片包的重组方式有所不同。
函数ip_conntrack_in()首先调用__ip_conntrack_proto_find(),根据数据包的协议找到其应该使用的传输协议的连接跟踪模块,接下来调用协议模块的error()对数据包进行正确性检查,然后调用函数resolve_normal_ct()选择正确的连接跟踪记录,如果没有,则创建一个新纪录。接着调用协议模块的packet()函数,如果返回失败,则nf_conntrack_put()将释放连接记录。ip_conntrack_in()函数的源码如下,函数resolve_normal_ct()实际操作了数据包和连接跟踪表的内容。
unsigned int ip_conntrack_in(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
struct ip_conntrack_protocol *proto;
int set_reply = 0;
int ret;
/* Previously seen (loopback or untracked)? Ignore. */
if ((*pskb)->nfct) {
CONNTRACK_STAT_INC_ATOMIC(ignore);
return NF_ACCEPT;
}
/* Never happen */
if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
if (net_ratelimit()) {
printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
(*pskb)->nh.iph->protocol, hooknum);
}
return NF_DROP;
}
......
/* rcu_read_lock()ed by nf_hook_slow */
proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol);
/* It may be an special packet, error, unclean...
* inverse of the return code tells to the netfilter
* core what to do with the packet. */
if (proto->error != NULL
&& (ret = proto->error(*pskb, &ctinfo, hooknum)) <= 0) {
CONNTRACK_STAT_INC_ATOMIC(error);
CONNTRACK_STAT_INC_ATOMIC(invalid);
return -ret;
}
if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) {
/* Not valid part of a connection */
CONNTRACK_STAT_INC_ATOMIC(invalid);
return NF_ACCEPT;
}
if (IS_ERR(ct)) {
/* Too stressed to deal. */
CONNTRACK_STAT_INC_ATOMIC(drop);
return NF_DROP;
}
IP_NF_ASSERT((*pskb)->nfct);
ret = proto->packet(ct, *pskb, ctinfo);
if (ret < 0) {
/* Invalid: inverse of the return code tells
* the netfilter core what to do*/
nf_conntrack_put((*pskb)->nfct);
(*pskb)->nfct = NULL;
CONNTRACK_STAT_INC_ATOMIC(invalid);
return -ret;
}
if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
ip_conntrack_event_cache(IPCT_STATUS, *pskb);
return ret;
}
|
函数resolve_normal_ct()搜索与传递来的sk_buff结构相匹配的连接记录,其首先调用函数ip_ct_get_tuple(),利用包的协议模块的pkt_to_tuple()函数创建一个ip_conntrack_tuple类型的结构,接下来调用函数ip_conntrack_find_get()在连接跟踪表中查找匹配的记录。如果没有找到匹配的项,将调用函数init_conntrack()创建一个新的连接跟踪记录。最后确定数据包sk_buff结构的状态域的值,对其中的nfct和nfctinfo进行赋值。函数resolve_normal_ct()的源码如下所示:
static inline struct ip_conntrack *
resolve_normal_ct(struct sk_buff *skb,
struct ip_conntrack_protocol *proto,
int *set_reply,
unsigned int hooknum,
enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack_tuple tuple;
struct ip_conntrack_tuple_hash *h;
struct ip_conntrack *ct;
IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4,
&tuple,proto))
return NULL;
/* look for tuple match */
h = ip_conntrack_find_get(&tuple, NULL);
if (!h) {
h = init_conntrack(&tuple, proto, skb);
if (!h)
return NULL;
if (IS_ERR(h))
return (void *)h;
}
ct = tuplehash_to_ctrack(h);
/* It exists; we have (non-exclusive) reference. */
if (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. */
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
DEBUGP("ip_conntrack_in: normal packet for %p\n",
ct);
*ctinfo = IP_CT_ESTABLISHED;
} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
DEBUGP("ip_conntrack_in: related packet for %p\n",
ct);
*ctinfo = IP_CT_RELATED;
} else {
DEBUGP("ip_conntrack_in: new packet for %p\n",
ct);
*ctinfo = IP_CT_NEW;
}
*set_reply = 0;
}
skb->nfct = &ct->ct_general;
skb->nfctinfo = *ctinfo;
return ct;
} |
[ 本帖最后由 Minit 于 2009-1-12 16:35 编辑 ] |
|