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

📄 ip_fw_compat_redir.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* This is a file to handle the "simple" NAT cases (redirect and   masquerade) required for the compatibility layer.   `bind to foreign address' and `getpeername' hacks are not   supported.   FIXME: Timing is overly simplistic.  If anyone complains, make it   use conntrack.*/#include <linux/config.h>#include <linux/netfilter.h>#include <linux/ip.h>#include <linux/udp.h>#include <linux/tcp.h>#include <net/checksum.h>#include <linux/timer.h>#include <linux/netdevice.h>#include <linux/if.h>#include <linux/in.h>#include <linux/netfilter_ipv4/lockhelp.h>static DECLARE_LOCK(redir_lock);#define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock)#define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)#include <linux/netfilter_ipv4/listhelp.h>#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endif#ifdef CONFIG_NETFILTER_DEBUG#define IP_NF_ASSERT(x)							 \do {									 \	if (!(x))							 \		/* Wooah!  I'm tripping my conntrack in a frenzy of	 \		   netplay... */					 \		printk("ASSERT: %s:%i(%s)\n",				 \		       __FILE__, __LINE__, __FUNCTION__);		 \} while(0);#else#define IP_NF_ASSERT(x)#endifstatic u_int16_tcheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck){	u_int32_t diffs[] = { oldvalinv, newval };	return csum_fold(csum_partial((char *)diffs, sizeof(diffs),				      oldcheck^0xFFFF));}struct redir_core {	u_int32_t orig_srcip, orig_dstip;	u_int16_t orig_sport, orig_dport;	u_int32_t new_dstip;	u_int16_t new_dport;};struct redir{	struct list_head list;	struct redir_core core;	struct timer_list destroyme;};static LIST_HEAD(redirs);static intredir_cmp(const struct redir *i,	  u_int32_t orig_srcip, u_int32_t orig_dstip,	  u_int16_t orig_sport, u_int16_t orig_dport){	return (i->core.orig_srcip == orig_srcip		&& i->core.orig_dstip == orig_dstip		&& i->core.orig_sport == orig_sport		&& i->core.orig_dport == orig_dport);}/* Search for an existing redirection of the TCP packet. */static struct redir *find_redir(u_int32_t orig_srcip, u_int32_t orig_dstip,	   u_int16_t orig_sport, u_int16_t orig_dport){	return LIST_FIND(&redirs, redir_cmp, struct redir *,			 orig_srcip, orig_dstip, orig_sport, orig_dport);}static void do_tcp_redir(struct sk_buff *skb, struct redir *redir){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph						+ iph->ihl);	tcph->check = cheat_check(~redir->core.orig_dstip,				  redir->core.new_dstip,				  cheat_check(redir->core.orig_dport ^ 0xFFFF,					      redir->core.new_dport,					      tcph->check));	iph->check = cheat_check(~redir->core.orig_dstip,				 redir->core.new_dstip, iph->check);	tcph->dest = redir->core.new_dport;	iph->daddr = redir->core.new_dstip;	skb->nfcache |= NFC_ALTERED;}static intunredir_cmp(const struct redir *i,	    u_int32_t new_dstip, u_int32_t orig_srcip,	    u_int16_t new_dport, u_int16_t orig_sport){	return (i->core.orig_srcip == orig_srcip		&& i->core.new_dstip == new_dstip		&& i->core.orig_sport == orig_sport		&& i->core.new_dport == new_dport);}/* Match reply packet against redir */static struct redir *find_unredir(u_int32_t new_dstip, u_int32_t orig_srcip,	     u_int16_t new_dport, u_int16_t orig_sport){	return LIST_FIND(&redirs, unredir_cmp, struct redir *,			 new_dstip, orig_srcip, new_dport, orig_sport);}/* `unredir' a reply packet. */static void do_tcp_unredir(struct sk_buff *skb, struct redir *redir){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph						+ iph->ihl);	tcph->check = cheat_check(~redir->core.new_dstip,				  redir->core.orig_dstip,				  cheat_check(redir->core.new_dport ^ 0xFFFF,					      redir->core.orig_dport,					      tcph->check));	iph->check = cheat_check(~redir->core.new_dstip,				 redir->core.orig_dstip,				 iph->check);	tcph->source = redir->core.orig_dport;	iph->saddr = redir->core.orig_dstip;	skb->nfcache |= NFC_ALTERED;}/* REDIRECT a packet. */unsigned intdo_redirect(struct sk_buff *skb,	    const struct net_device *dev,	    u_int16_t redirpt){	struct iphdr *iph = skb->nh.iph;	u_int32_t newdst;	/* Figure out address: not loopback. */	if (!dev)		return NF_DROP;	/* Grab first address on interface. */	newdst = ((struct in_device *)dev->ip_ptr)->ifa_list->ifa_local;	switch (iph->protocol) {	case IPPROTO_UDP: {		/* Simple mangle. */		struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph							+ iph->ihl);		if (udph->check) /* 0 is a special case meaning no checksum */			udph->check = cheat_check(~iph->daddr, newdst,					  cheat_check(udph->dest ^ 0xFFFF,						      redirpt,						      udph->check));		iph->check = cheat_check(~iph->daddr, newdst, iph->check);		udph->dest = redirpt;		iph->daddr = newdst;		skb->nfcache |= NFC_ALTERED;		return NF_ACCEPT;	}	case IPPROTO_TCP: {		/* Mangle, maybe record. */		struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph							+ iph->ihl);		struct redir *redir;		int ret;		DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n",		       iph->saddr, tcph->source, iph->daddr, tcph->dest,		       newdst, redirpt);		LOCK_BH(&redir_lock);		redir = find_redir(iph->saddr, iph->daddr,				   tcph->source, tcph->dest);		if (!redir) {			redir = kmalloc(sizeof(struct redir), GFP_ATOMIC);			if (!redir) {				ret = NF_DROP;				goto out;			}			list_prepend(&redirs, redir);			init_timer(&redir->destroyme);		}		/* In case mangling has changed, rewrite this part. */		redir->core = ((struct redir_core)			       { iph->saddr, iph->daddr,				 tcph->source, tcph->dest,				 newdst, redirpt });		do_tcp_redir(skb, redir);		ret = NF_ACCEPT;	out:		UNLOCK_BH(&redir_lock);		return ret;	}	default: /* give up if not TCP or UDP. */		return NF_DROP;	}}static void destroyme(unsigned long me){	LOCK_BH(&redir_lock);	LIST_DELETE(&redirs, (struct redir *)me);	UNLOCK_BH(&redir_lock);}/* Incoming packet: is it a reply to a masqueraded connection, or   part of an already-redirected TCP connection? */voidcheck_for_redirect(struct sk_buff *skb){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph						+ iph->ihl);	struct redir *redir;	if (iph->protocol != IPPROTO_TCP)		return;	LOCK_BH(&redir_lock);	redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest);	if (redir) {		DEBUGP("Doing tcp redirect again.\n");		do_tcp_redir(skb, redir);		if (tcph->rst || tcph->fin) {			redir->destroyme.function = destroyme;			redir->destroyme.data = (unsigned long)redir;			mod_timer(&redir->destroyme, 75*HZ);		}	}	UNLOCK_BH(&redir_lock);}voidcheck_for_unredirect(struct sk_buff *skb){	struct iphdr *iph = skb->nh.iph;	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph						+ iph->ihl);	struct redir *redir;	if (iph->protocol != IPPROTO_TCP)		return;	LOCK_BH(&redir_lock);	redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest);	if (redir) {		DEBUGP("Doing tcp unredirect.\n");		do_tcp_unredir(skb, redir);		if (tcph->rst || tcph->fin) {			redir->destroyme.function = destroyme;			redir->destroyme.data = (unsigned long)redir;			mod_timer(&redir->destroyme, 75*HZ);		}	}	UNLOCK_BH(&redir_lock);}

⌨️ 快捷键说明

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