⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip_conntrack_core.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
           generated ICMP errors --RR */	if (!(h->ctrack->status & IPS_CONFIRMED)	    && hooknum != NF_IP_LOCAL_OUT) {		DEBUGP("icmp_error_track: unconfirmed\n");		ip_conntrack_put(h->ctrack);		return NULL;	}	/* Update skb to refer to this connection */	skb->nfct = &h->ctrack->infos[*ctinfo];	return h->ctrack;}/* There's a small race here where we may free a just-replied to   connection.  Too bad: we're in trouble anyway. */static inline int unreplied(const struct ip_conntrack_tuple_hash *i){	/* Unconfirmed connections either really fresh or transitory           anyway */	if (!(i->ctrack->status & IPS_ASSURED)	    && (i->ctrack->status & IPS_CONFIRMED))		return 1;	return 0;}static int early_drop(struct list_head *chain){	/* Traverse backwards: gives us oldest, which is roughly LRU */	struct ip_conntrack_tuple_hash *h;	int dropped = 0;	READ_LOCK(&ip_conntrack_lock);	h = LIST_FIND(chain, unreplied, struct ip_conntrack_tuple_hash *);	if (h)		atomic_inc(&h->ctrack->ct_general.use);	READ_UNLOCK(&ip_conntrack_lock);	if (!h)		return dropped;	if (del_timer(&h->ctrack->timeout)) {		death_by_timeout((unsigned long)h->ctrack);		dropped = 1;	}	ip_conntrack_put(h->ctrack);	return dropped;}static inline int helper_cmp(const struct ip_conntrack_helper *i,			     const struct ip_conntrack_tuple *rtuple){	return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);}/* Compare parts depending on mask. */static inline int expect_cmp(const struct ip_conntrack_expect *i,			     const struct ip_conntrack_tuple *tuple){	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);}/* Allocate a new conntrack; we set everything up, then grab write   lock and see if we lost a race.  If we lost it we return 0,   indicating the controlling code should look again. */static intinit_conntrack(const struct ip_conntrack_tuple *tuple,	       struct ip_conntrack_protocol *protocol,	       struct sk_buff *skb){	struct ip_conntrack *conntrack;	struct ip_conntrack_tuple repl_tuple;	size_t hash, repl_hash;	struct ip_conntrack_expect *expected;	enum ip_conntrack_info ctinfo;	unsigned long extra_jiffies;	int i;	static unsigned int drop_next = 0;	hash = hash_conntrack(tuple);	if (ip_conntrack_max &&	    atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {		if (net_ratelimit())			printk(KERN_WARNING "ip_conntrack: maximum limit of"			       " %d entries exceeded\n", ip_conntrack_max);		/* Try dropping from random chain, or else from the                   chain about to put into (in case they're trying to                   bomb one hash chain). */		if (drop_next >= ip_conntrack_htable_size)			drop_next = 0;		if (!early_drop(&ip_conntrack_hash[drop_next++])		    && !early_drop(&ip_conntrack_hash[hash]))			return 1;	}	if (!invert_tuple(&repl_tuple, tuple, protocol)) {		DEBUGP("Can't invert tuple.\n");		return 1;	}	repl_hash = hash_conntrack(&repl_tuple);	conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);	if (!conntrack) {		DEBUGP("Can't allocate conntrack.\n");		return 1;	}	memset(conntrack, 0, sizeof(struct ip_conntrack));	atomic_set(&conntrack->ct_general.use, 1);	conntrack->ct_general.destroy = destroy_conntrack;	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;	conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;	for (i=0; i < IP_CT_NUMBER; i++)		conntrack->infos[i].master = &conntrack->ct_general;	extra_jiffies = protocol->new(conntrack, skb->nh.iph, skb->len);	if (!extra_jiffies) {		kmem_cache_free(ip_conntrack_cachep, conntrack);		return 1;	}	/* Don't set timer yet: wait for confirmation */	init_timer(&conntrack->timeout);	conntrack->timeout.data = (unsigned long)conntrack;	conntrack->timeout.function = death_by_timeout;	conntrack->timeout.expires = extra_jiffies;	/* Sew in at head of hash list. */	WRITE_LOCK(&ip_conntrack_lock);	/* Check noone else beat us in the race... */	if (__ip_conntrack_find(tuple, NULL)) {		WRITE_UNLOCK(&ip_conntrack_lock);		kmem_cache_free(ip_conntrack_cachep, conntrack);		return 0;	}	conntrack->helper = LIST_FIND(&helpers, helper_cmp,				      struct ip_conntrack_helper *,				      &repl_tuple);	/* Need finding and deleting of expected ONLY if we win race */	expected = LIST_FIND(&expect_list, expect_cmp,			     struct ip_conntrack_expect *, tuple);	if (expected) {		/* Welcome, Mr. Bond.  We've been expecting you... */		conntrack->status = IPS_EXPECTED;		conntrack->master.master = &expected->expectant->ct_general;		IP_NF_ASSERT(conntrack->master.master);		LIST_DELETE(&expect_list, expected);		expected->expectant = NULL;		nf_conntrack_get(&conntrack->master);		ctinfo = IP_CT_RELATED;	} else {		ctinfo = IP_CT_NEW;	}	list_prepend(&ip_conntrack_hash[hash],		     &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]);	list_prepend(&ip_conntrack_hash[repl_hash],		     &conntrack->tuplehash[IP_CT_DIR_REPLY]);	atomic_inc(&ip_conntrack_count);	WRITE_UNLOCK(&ip_conntrack_lock);	/* Update skb to refer to this connection */	skb->nfct = &conntrack->infos[ctinfo];	if (expected && expected->expectfn)		expected->expectfn(conntrack);	return 1;}/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */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;	IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);	if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))		return NULL;	/* Loop around search/insert race */	do {		/* look for tuple match */		h = ip_conntrack_find_get(&tuple, NULL);		if (!h && init_conntrack(&tuple, proto, skb))			return NULL;	} while (!h);	/* It exists; we have (non-exclusive) reference. */	if (DIRECTION(h) == IP_CT_DIR_REPLY) {		/* Reply on unconfirmed connection => unclassifiable */		if (!(h->ctrack->status & IPS_CONFIRMED)) {			/* Exception: local TCP RSTs (generated by                           REJECT target). */			if (hooknum == NF_IP_LOCAL_OUT			    && h->tuple.dst.protonum == IPPROTO_TCP) {				const struct tcphdr *tcph					= (const struct tcphdr *)					((u_int32_t *)skb->nh.iph					 + skb->nh.iph->ihl);				if (tcph->rst) {					*ctinfo	= IP_CT_ESTABLISHED						+ IP_CT_IS_REPLY;					*set_reply = 0;					goto set_skb;				}			}			DEBUGP("Reply on unconfirmed connection\n");			ip_conntrack_put(h->ctrack);			return NULL;		}		*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 (h->ctrack->status & IPS_SEEN_REPLY) {			DEBUGP("ip_conntrack_in: normal packet for %p\n",			       h->ctrack);		        *ctinfo = IP_CT_ESTABLISHED;		} else if (h->ctrack->status & IPS_EXPECTED) {			DEBUGP("ip_conntrack_in: related packet for %p\n",			       h->ctrack);			*ctinfo = IP_CT_RELATED;		} else {			DEBUGP("ip_conntrack_in: new packet for %p\n",			       h->ctrack);			*ctinfo = IP_CT_NEW;		}		*set_reply = 0;	} set_skb:	skb->nfct = &h->ctrack->infos[*ctinfo];	return h->ctrack;}/* Return conntrack and conntrack_info a given skb */inline struct ip_conntrack *ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo){	if (skb->nfct) {		struct ip_conntrack *ct			= (struct ip_conntrack *)skb->nfct->master;		/* ctinfo is the index of the nfct inside the conntrack */		*ctinfo = skb->nfct - ct->infos;		IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);		return ct;	}	return NULL;}/* Netfilter hook itself. */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;	int ret;	/* FIXME: Do this right please. --RR */	(*pskb)->nfcache |= NFC_UNKNOWN;/* Doesn't cover locally-generated broadcast, so not worth it. */#if 0	/* Ignore broadcast: no `connection'. */	if ((*pskb)->pkt_type == PACKET_BROADCAST) {		printk("Broadcast packet!\n");		return NF_ACCEPT;	} else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF)) 		   == htonl(0x000000FF)) {		printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",		       NIPQUAD((*pskb)->nh.iph->saddr),		       NIPQUAD((*pskb)->nh.iph->daddr),		       (*pskb)->sk, (*pskb)->pkt_type);	}#endif	/* Previously seen (loopback)?  Ignore.  Do this before           fragment check. */	if ((*pskb)->nfct)		return NF_ACCEPT;	/* Gather fragments. */	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {		*pskb = ip_ct_gather_frags(*pskb);		if (!*pskb)			return NF_STOLEN;	}	proto = find_proto((*pskb)->nh.iph->protocol);	/* It may be an icmp error... */	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 	    && icmp_error_track(*pskb, &ctinfo, hooknum))		return NF_ACCEPT;	if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))		/* Not valid part of a connection */		return NF_ACCEPT;	IP_NF_ASSERT((*pskb)->nfct);	ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);	if (ret == -1) {		/* Invalid */		nf_conntrack_put((*pskb)->nfct);		(*pskb)->nfct = NULL;		return NF_ACCEPT;	}	if (ret != NF_DROP && ct->helper) {		ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,				       ct, ctinfo);		if (ret == -1) {			/* Invalid */			nf_conntrack_put((*pskb)->nfct);			(*pskb)->nfct = NULL;			return NF_ACCEPT;		}	}	if (set_reply)		set_bit(IPS_SEEN_REPLY_BIT, &ct->status);	return ret;}int invert_tuplepr(struct ip_conntrack_tuple *inverse,		   const struct ip_conntrack_tuple *orig){	return invert_tuple(inverse, orig, find_proto(orig->dst.protonum));}static void unexpect_related(struct ip_conntrack *related_to){	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);	list_del(&related_to->expected.list);	related_to->expected.expectant = NULL;}/* Would two expected things clash? */static inline int expect_clash(const struct ip_conntrack_expect *i,			       const struct ip_conntrack_expect *new){	/* Part covered by intersection of masks must be unequal,           otherwise they clash */	struct ip_conntrack_tuple intersect_mask		= { { i->mask.src.ip & new->mask.src.ip,		      { i->mask.src.u.all & new->mask.src.u.all } },		    { i->mask.dst.ip & new->mask.dst.ip,		      { i->mask.dst.u.all & new->mask.dst.u.all },		      i->mask.dst.protonum & new->mask.dst.protonum } };	return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);}/* Add a related connection. */int ip_conntrack_expect_related(struct ip_conntrack *related_to,				const struct ip_conntrack_tuple *tuple,				const struct ip_conntrack_tuple *mask,				int (*expectfn)(struct ip_conntrack *)){	WRITE_LOCK(&ip_conntrack_lock);	if (related_to->expected.expectant)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -