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

📄 ip_conntrack_core.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Connection state tracking for netfilter.  This is separated from,   but required by, the NAT layer; it can also be used by an iptables   extension. *//* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General   Public Licence. */#ifdef MODULE#define __NO_VERSION__#endif#include <linux/version.h>#include <linux/config.h>#include <linux/types.h>#include <linux/ip.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <linux/brlock.h>#include <net/checksum.h>#include <linux/stddef.h>#include <linux/sysctl.h>#include <linux/slab.h>/* For ERR_PTR().  Yeah, I know... --RR */#include <linux/fs.h>/* This rwlock protects the main hash table, protocol/helper/expected   registrations, conntrack timers*/#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)#include <linux/netfilter_ipv4/ip_conntrack.h>#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>#include <linux/netfilter_ipv4/ip_conntrack_helper.h>#include <linux/netfilter_ipv4/ip_conntrack_core.h>#include <linux/netfilter_ipv4/listhelp.h>#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endifDECLARE_RWLOCK(ip_conntrack_lock);void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;LIST_HEAD(expect_list);LIST_HEAD(protocol_list);static LIST_HEAD(helpers);unsigned int ip_conntrack_htable_size = 0;static int ip_conntrack_max = 0;static atomic_t ip_conntrack_count = ATOMIC_INIT(0);struct list_head *ip_conntrack_hash;static kmem_cache_t *ip_conntrack_cachep;extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,			      u_int8_t protocol){	return protocol == curr->proto;}struct ip_conntrack_protocol *__find_proto(u_int8_t protocol){	struct ip_conntrack_protocol *p;	MUST_BE_READ_LOCKED(&ip_conntrack_lock);	p = LIST_FIND(&protocol_list, proto_cmpfn,		      struct ip_conntrack_protocol *, protocol);	if (!p)		p = &ip_conntrack_generic_protocol;	return p;}struct ip_conntrack_protocol *find_proto(u_int8_t protocol){	struct ip_conntrack_protocol *p;	READ_LOCK(&ip_conntrack_lock);	p = __find_proto(protocol);	READ_UNLOCK(&ip_conntrack_lock);	return p;}static inline void ip_conntrack_put(struct ip_conntrack *ct){	IP_NF_ASSERT(ct);	IP_NF_ASSERT(ct->infos[0].master);	/* nf_conntrack_put wants to go via an info struct, so feed it           one at random. */	nf_conntrack_put(&ct->infos[0]);}static inline u_int32_thash_conntrack(const struct ip_conntrack_tuple *tuple){#if 0	dump_tuple(tuple);#endif	/* ntohl because more differences in low bits. */	/* To ensure that halves of the same connection don't hash	   clash, we add the source per-proto again. */	return (ntohl(tuple->src.ip + tuple->dst.ip		     + tuple->src.u.all + tuple->dst.u.all		     + tuple->dst.protonum)		+ ntohs(tuple->src.u.all))		% ip_conntrack_htable_size;}inline intget_tuple(const struct iphdr *iph, size_t len,	  struct ip_conntrack_tuple *tuple,	  struct ip_conntrack_protocol *protocol){	int ret;	/* Never happen */	if (iph->frag_off & htons(IP_OFFSET)) {		printk("ip_conntrack_core: Frag of proto %u.\n",		       iph->protocol);		return 0;	}	/* Guarantee 8 protocol bytes: if more wanted, use len param */	else if (iph->ihl * 4 + 8 > len)		return 0;	tuple->src.ip = iph->saddr;	tuple->dst.ip = iph->daddr;	tuple->dst.protonum = iph->protocol;	ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,				     len - 4*iph->ihl,				     tuple);	return ret;}static intinvert_tuple(struct ip_conntrack_tuple *inverse,	     const struct ip_conntrack_tuple *orig,	     const struct ip_conntrack_protocol *protocol){	inverse->src.ip = orig->dst.ip;	inverse->dst.ip = orig->src.ip;	inverse->dst.protonum = orig->dst.protonum;	return protocol->invert_tuple(inverse, orig);}static voidclean_from_lists(struct ip_conntrack *ct){	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);	/* Remove from both hash lists: must not NULL out next ptrs,           otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE           doesn't do this. --RR */	LIST_DELETE(&ip_conntrack_hash		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);	LIST_DELETE(&ip_conntrack_hash		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],		    &ct->tuplehash[IP_CT_DIR_REPLY]);	/* If our expected is in the list, take it out. */	if (ct->expected.expectant) {		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));		IP_NF_ASSERT(ct->expected.expectant == ct);		LIST_DELETE(&expect_list, &ct->expected);	}}static voiddestroy_conntrack(struct nf_conntrack *nfct){	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);	IP_NF_ASSERT(!timer_pending(&ct->timeout));	if (ct->master.master)		nf_conntrack_put(&ct->master);	if (ip_conntrack_destroyed)		ip_conntrack_destroyed(ct);	kmem_cache_free(ip_conntrack_cachep, ct);	atomic_dec(&ip_conntrack_count);}static void death_by_timeout(unsigned long ul_conntrack){	struct ip_conntrack *ct = (void *)ul_conntrack;	WRITE_LOCK(&ip_conntrack_lock);	clean_from_lists(ct);	WRITE_UNLOCK(&ip_conntrack_lock);	ip_conntrack_put(ct);}static inline intconntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,		    const struct ip_conntrack_tuple *tuple,		    const struct ip_conntrack *ignored_conntrack){	MUST_BE_READ_LOCKED(&ip_conntrack_lock);	return i->ctrack != ignored_conntrack		&& ip_ct_tuple_equal(tuple, &i->tuple);}static struct ip_conntrack_tuple_hash *__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,		    const struct ip_conntrack *ignored_conntrack){	struct ip_conntrack_tuple_hash *h;	MUST_BE_READ_LOCKED(&ip_conntrack_lock);	h = LIST_FIND(&ip_conntrack_hash[hash_conntrack(tuple)],		      conntrack_tuple_cmp,		      struct ip_conntrack_tuple_hash *,		      tuple, ignored_conntrack);	return h;}/* Find a connection corresponding to a tuple. */struct ip_conntrack_tuple_hash *ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,		      const struct ip_conntrack *ignored_conntrack){	struct ip_conntrack_tuple_hash *h;	READ_LOCK(&ip_conntrack_lock);	h = __ip_conntrack_find(tuple, ignored_conntrack);	if (h)		atomic_inc(&h->ctrack->ct_general.use);	READ_UNLOCK(&ip_conntrack_lock);	return h;}static inline struct ip_conntrack *__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo){	struct ip_conntrack *ct		= (struct ip_conntrack *)nfct->master;	/* ctinfo is the index of the nfct inside the conntrack */	*ctinfo = nfct - ct->infos;	IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);	return ct;}/* Return conntrack and conntrack_info given skb->nfct->master */struct ip_conntrack *ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo){	if (skb->nfct) 		return __ip_conntrack_get(skb->nfct, ctinfo);	return NULL;}/* Confirm a connection given skb->nfct; places it in hash table */int__ip_conntrack_confirm(struct nf_ct_info *nfct){	unsigned int hash, repl_hash;	struct ip_conntrack *ct;	enum ip_conntrack_info ctinfo;	ct = __ip_conntrack_get(nfct, &ctinfo);	/* ipt_REJECT uses ip_conntrack_attach to attach related	   ICMP/TCP RST packets in other direction.  Actual packet	   which created connection will be IP_CT_NEW or for an	   expected connection, IP_CT_RELATED. */	if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)		return NF_ACCEPT;	hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);	repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);	/* We're not in hash table, and we refuse to set up related	   connections for unconfirmed conns.  But packet copies and	   REJECT will give spurious warnings here. */	/* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */	/* No external references means noone else could have           confirmed us. */	IP_NF_ASSERT(!is_confirmed(ct));	DEBUGP("Confirming conntrack %p\n", ct);	WRITE_LOCK(&ip_conntrack_lock);	/* See if there's one in the list already, including reverse:           NAT could have grabbed it without realizing, since we're           not in the hash.  If there is, we lost race. */	if (!LIST_FIND(&ip_conntrack_hash[hash],		       conntrack_tuple_cmp,		       struct ip_conntrack_tuple_hash *,		       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)	    && !LIST_FIND(&ip_conntrack_hash[repl_hash],			  conntrack_tuple_cmp,			  struct ip_conntrack_tuple_hash *,			  &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {		list_prepend(&ip_conntrack_hash[hash],			     &ct->tuplehash[IP_CT_DIR_ORIGINAL]);		list_prepend(&ip_conntrack_hash[repl_hash],			     &ct->tuplehash[IP_CT_DIR_REPLY]);		/* Timer relative to confirmation time, not original		   setting time, otherwise we'd get timer wrap in		   wierd delay cases. */		ct->timeout.expires += jiffies;		add_timer(&ct->timeout);		atomic_inc(&ct->ct_general.use);		WRITE_UNLOCK(&ip_conntrack_lock);		return NF_ACCEPT;	}	WRITE_UNLOCK(&ip_conntrack_lock);	return NF_DROP;}/* Returns true if a connection correspondings to the tuple (required   for NAT). */intip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,			 const struct ip_conntrack *ignored_conntrack){	struct ip_conntrack_tuple_hash *h;	READ_LOCK(&ip_conntrack_lock);	h = __ip_conntrack_find(tuple, ignored_conntrack);	READ_UNLOCK(&ip_conntrack_lock);	return h != NULL;}/* Returns conntrack if it dealt with ICMP, and filled in skb fields */struct ip_conntrack *icmp_error_track(struct sk_buff *skb,		 enum ip_conntrack_info *ctinfo,		 unsigned int hooknum){	const struct iphdr *iph;	struct icmphdr *hdr;	struct ip_conntrack_tuple innertuple, origtuple;	struct iphdr *inner;	size_t datalen;	struct ip_conntrack_protocol *innerproto;	struct ip_conntrack_tuple_hash *h;	IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);	IP_NF_ASSERT(skb->nfct == NULL);	iph = skb->nh.iph;	hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);	inner = (struct iphdr *)(hdr + 1);	datalen = skb->len - iph->ihl*4 - sizeof(*hdr);	if (skb->len < iph->ihl * 4 + sizeof(*hdr) + sizeof(*iph)) {		DEBUGP("icmp_error_track: too short\n");		return NULL;	}	if (hdr->type != ICMP_DEST_UNREACH	    && hdr->type != ICMP_SOURCE_QUENCH	    && hdr->type != ICMP_TIME_EXCEEDED	    && hdr->type != ICMP_PARAMETERPROB	    && hdr->type != ICMP_REDIRECT)		return NULL;	/* Ignore ICMP's containing fragments (shouldn't happen) */	if (inner->frag_off & htons(IP_OFFSET)) {		DEBUGP("icmp_error_track: fragment of proto %u\n",		       inner->protocol);		return NULL;	}	/* Ignore it if the checksum's bogus. */	if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {		DEBUGP("icmp_error_track: bad csum\n");		return NULL;	}

⌨️ 快捷键说明

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