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

📄 ip_conntrack_core.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		unexpect_related(related_to);	related_to->expected.tuple = *tuple;	related_to->expected.mask = *mask;	related_to->expected.expectfn = expectfn;	if (LIST_FIND(&expect_list, expect_clash,		      struct ip_conntrack_expect *, &related_to->expected)) {		WRITE_UNLOCK(&ip_conntrack_lock);		return -EBUSY;	}	list_prepend(&expect_list, &related_to->expected);	related_to->expected.expectant = related_to;	WRITE_UNLOCK(&ip_conntrack_lock);	return 0;}void ip_conntrack_unexpect_related(struct ip_conntrack *related_to){	WRITE_LOCK(&ip_conntrack_lock);	unexpect_related(related_to);	WRITE_UNLOCK(&ip_conntrack_lock);}	/* Alter reply tuple (maybe alter helper).  If it's already taken,   return 0 and don't do alteration. */int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,			     const struct ip_conntrack_tuple *newreply){	unsigned int newindex = hash_conntrack(newreply);	WRITE_LOCK(&ip_conntrack_lock);	if (__ip_conntrack_find(newreply, conntrack)) {		WRITE_UNLOCK(&ip_conntrack_lock);		return 0;	}	DEBUGP("Altering reply tuple of %p to ", conntrack);	DUMP_TUPLE(newreply);	LIST_DELETE(&ip_conntrack_hash		    [hash_conntrack(&conntrack->tuplehash[IP_CT_DIR_REPLY]				    .tuple)],		    &conntrack->tuplehash[IP_CT_DIR_REPLY]);	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;	list_prepend(&ip_conntrack_hash[newindex],		     &conntrack->tuplehash[IP_CT_DIR_REPLY]);	conntrack->helper = LIST_FIND(&helpers, helper_cmp,				      struct ip_conntrack_helper *,				      newreply);	WRITE_UNLOCK(&ip_conntrack_lock);	return 1;}int ip_conntrack_helper_register(struct ip_conntrack_helper *me){	MOD_INC_USE_COUNT;	WRITE_LOCK(&ip_conntrack_lock);	list_prepend(&helpers, me);	WRITE_UNLOCK(&ip_conntrack_lock);	return 0;}static inline int unhelp(struct ip_conntrack_tuple_hash *i,			 const struct ip_conntrack_helper *me){	if (i->ctrack->helper == me) {		i->ctrack->helper = NULL;		/* Get rid of any expected. */		if (i->ctrack->expected.expectant) {			IP_NF_ASSERT(i->ctrack->expected.expectant				     == i->ctrack);			LIST_DELETE(&expect_list, &i->ctrack->expected);			i->ctrack->expected.expectant = NULL;		}	}	return 0;}void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me){	unsigned int i;	/* Need write lock here, to delete helper. */	WRITE_LOCK(&ip_conntrack_lock);	LIST_DELETE(&helpers, me);	/* Get rid of expecteds, set helpers to NULL. */	for (i = 0; i < ip_conntrack_htable_size; i++)		LIST_FIND_W(&ip_conntrack_hash[i], unhelp,			    struct ip_conntrack_tuple_hash *, me);	WRITE_UNLOCK(&ip_conntrack_lock);	/* Someone could be still looking at the helper in a bh. */	br_write_lock_bh(BR_NETPROTO_LOCK);	br_write_unlock_bh(BR_NETPROTO_LOCK);	MOD_DEC_USE_COUNT;}/* Refresh conntrack for this many jiffies. */void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies){	IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);	WRITE_LOCK(&ip_conntrack_lock);	/* Timer may not be active yet */	if (!(ct->status & IPS_CONFIRMED))		ct->timeout.expires = extra_jiffies;	else {		/* Need del_timer for race avoidance (may already be dying). */		if (del_timer(&ct->timeout)) {			ct->timeout.expires = jiffies + extra_jiffies;			add_timer(&ct->timeout);		}	}	WRITE_UNLOCK(&ip_conntrack_lock);}/* Returns new sk_buff, or NULL */struct sk_buff *ip_ct_gather_frags(struct sk_buff *skb){	struct sock *sk = skb->sk;#ifdef CONFIG_NETFILTER_DEBUG	unsigned int olddebug = skb->nf_debug;#endif	if (sk) sock_hold(sk);	local_bh_disable(); 	skb = ip_defrag(skb);	local_bh_enable(); 	if (!skb) {		if (sk) sock_put(sk);		return skb;	}	if (sk) {		skb_set_owner_w(skb, sk);		sock_put(sk);	}	ip_send_check(skb->nh.iph);	skb->nfcache |= NFC_ALTERED;#ifdef CONFIG_NETFILTER_DEBUG	/* Packet path as if nothing had happened. */	skb->nf_debug = olddebug;#endif	return skb;}static inline intdo_kill(const struct ip_conntrack_tuple_hash *i,	int (*kill)(const struct ip_conntrack *i, void *data),	void *data){	return kill(i->ctrack, data);}/* Bring out ya dead! */static struct ip_conntrack_tuple_hash *get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),		void *data){	struct ip_conntrack_tuple_hash *h = NULL;	unsigned int i;	READ_LOCK(&ip_conntrack_lock);	for (i = 0; !h && i < ip_conntrack_htable_size; i++) {		h = LIST_FIND(&ip_conntrack_hash[i], do_kill,			      struct ip_conntrack_tuple_hash *, kill, data);	}	if (h)		atomic_inc(&h->ctrack->ct_general.use);	READ_UNLOCK(&ip_conntrack_lock);	return h;}voidip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),			void *data){	struct ip_conntrack_tuple_hash *h;	/* This is order n^2, by the way. */	while ((h = get_next_corpse(kill, data)) != NULL) {		/* Time to push up daises... */		if (del_timer(&h->ctrack->timeout))			death_by_timeout((unsigned long)h->ctrack);		else if (!(h->ctrack->status & IPS_CONFIRMED)) {			/* Unconfirmed connection.  Clean from lists,			   mark confirmed so it gets cleaned as soon			   as skb freed. */			WRITE_LOCK(&ip_conntrack_lock);			/* Lock protects race against another setting                           of confirmed bit.  set_bit isolates this                           bit from the others. */			if (!(h->ctrack->status & IPS_CONFIRMED)) {				clean_from_lists(h->ctrack);				set_bit(IPS_CONFIRMED_BIT, &h->ctrack->status);			}			WRITE_UNLOCK(&ip_conntrack_lock);		}		/* ... else the timer will get him soon. */		ip_conntrack_put(h->ctrack);	}}/* Fast function for those who don't want to parse /proc (and I don't   blame them). *//* Reversing the socket's dst/src point of view gives us the reply   mapping. */static intgetorigdst(struct sock *sk, int optval, void *user, int *len){	struct ip_conntrack_tuple_hash *h;	struct ip_conntrack_tuple tuple = { { sk->rcv_saddr, { sk->sport } },					    { sk->daddr, { sk->dport },					      IPPROTO_TCP } };	/* We only do TCP at the moment: is there a better way? */	if (strcmp(sk->prot->name, "TCP") != 0) {		DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");		return -ENOPROTOOPT;	}	if (*len != sizeof(struct sockaddr_in)) {		DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",		       *len, sizeof(struct sockaddr_in));		return -EINVAL;	}	h = ip_conntrack_find_get(&tuple, NULL);	if (h) {		struct sockaddr_in sin;		sin.sin_family = AF_INET;		sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]			.tuple.dst.u.tcp.port;		sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]			.tuple.dst.ip;		DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",		       NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));		ip_conntrack_put(h->ctrack);		if (copy_to_user(user, &sin, sizeof(sin)) != 0)			return -EFAULT;		else			return 0;	}	DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",	       NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),	       NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));	return -ENOENT;}static struct nf_sockopt_ops so_getorigdst= { { NULL, NULL }, PF_INET,    0, 0, NULL, /* Setsockopts */    SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst,    0, NULL };#define NET_IP_CONNTRACK_MAX 2089#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"#ifdef CONFIG_SYSCTLstatic struct ctl_table_header *ip_conntrack_sysctl_header;static ctl_table ip_conntrack_table[] = {	{ NET_IP_CONNTRACK_MAX, NET_IP_CONNTRACK_MAX_NAME, &ip_conntrack_max,	  sizeof(ip_conntrack_max), 0644,  NULL, proc_dointvec }, 	{ 0 }};static ctl_table ip_conntrack_dir_table[] = {	{NET_IPV4, "ipv4", NULL, 0, 0555, ip_conntrack_table, 0, 0, 0, 0, 0},	{ 0 }};static ctl_table ip_conntrack_root_table[] = {	{CTL_NET, "net", NULL, 0, 0555, ip_conntrack_dir_table, 0, 0, 0, 0, 0},	{ 0 }};#endif /*CONFIG_SYSCTL*/static int kill_all(const struct ip_conntrack *i, void *data){	return 1;}/* Mishearing the voices in his head, our hero wonders how he's   supposed to kill the mall. */void ip_conntrack_cleanup(void){#ifdef CONFIG_SYSCTL	unregister_sysctl_table(ip_conntrack_sysctl_header);#endif  i_see_dead_people:	ip_ct_selective_cleanup(kill_all, NULL);	if (atomic_read(&ip_conntrack_count) != 0) {		schedule();		goto i_see_dead_people;	}	kmem_cache_destroy(ip_conntrack_cachep);	vfree(ip_conntrack_hash);	nf_unregister_sockopt(&so_getorigdst);}int __init ip_conntrack_init(void){	unsigned int i;	int ret;	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB	 * machine has 256 buckets.  1GB machine has 8192 buckets. */	ip_conntrack_htable_size		= (((num_physpages << PAGE_SHIFT) / 16384)		   / sizeof(struct list_head));	ip_conntrack_max = 8 * ip_conntrack_htable_size;	printk("ip_conntrack (%u buckets, %d max)\n",	       ip_conntrack_htable_size, ip_conntrack_max);	ret = nf_register_sockopt(&so_getorigdst);	if (ret != 0)		return ret;	ip_conntrack_hash = vmalloc(sizeof(struct list_head)				    * ip_conntrack_htable_size);	if (!ip_conntrack_hash) {		nf_unregister_sockopt(&so_getorigdst);		return -ENOMEM;	}	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",	                                        sizeof(struct ip_conntrack), 0,	                                        SLAB_HWCACHE_ALIGN, NULL, NULL);	if (!ip_conntrack_cachep) {		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");		vfree(ip_conntrack_hash);		nf_unregister_sockopt(&so_getorigdst);		return -ENOMEM;	}		/* Don't NEED lock here, but good form anyway. */	WRITE_LOCK(&ip_conntrack_lock);	/* Sew in builtin protocols. */	list_append(&protocol_list, &ip_conntrack_protocol_tcp);	list_append(&protocol_list, &ip_conntrack_protocol_udp);	list_append(&protocol_list, &ip_conntrack_protocol_icmp);	WRITE_UNLOCK(&ip_conntrack_lock);	for (i = 0; i < ip_conntrack_htable_size; i++)		INIT_LIST_HEAD(&ip_conntrack_hash[i]);/* This is fucking braindead.  There is NO WAY of doing this without   the CONFIG_SYSCTL unless you don't want to detect errors.   Grrr... --RR */#ifdef CONFIG_SYSCTL	ip_conntrack_sysctl_header		= register_sysctl_table(ip_conntrack_root_table, 0);	if (ip_conntrack_sysctl_header == NULL) {		kmem_cache_destroy(ip_conntrack_cachep);		vfree(ip_conntrack_hash);		nf_unregister_sockopt(&so_getorigdst);		return -ENOMEM;	}#endif /*CONFIG_SYSCTL*/	return ret;}

⌨️ 快捷键说明

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