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

📄 ip_masq.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * * 	Masquerading functionality * * 	Copyright (c) 1994 Pauline Middelink * *	$Id: ip_masq.c,v 1.34.2.2 1999/08/07 10:56:28 davem Exp $ * * *	See ip_fw.c for original log * * Fixes: *	Joseph Gooch		:	Modified ip_fw_masquerade() to do a ip_route_output() *	 (help by Dan Drown)	:	to choose the proper local address. *	 (and Alexey)		: *	Juan Jose Ciarlante	:	Modularized application masquerading (see ip_masq_app.c) *	Juan Jose Ciarlante	:	New struct ip_masq_seq that holds output/input delta seq. *	Juan Jose Ciarlante	:	Added hashed lookup by proto,maddr,mport and proto,saddr,sport *	Juan Jose Ciarlante	:	Fixed deadlock if free ports get exhausted *	Juan Jose Ciarlante	:	Added NO_ADDR status flag. *	Richard Lynch		:	Added IP Autoforward *	Nigel Metheringham	:	Added ICMP handling for demasquerade *	Nigel Metheringham	:	Checksum checking of masqueraded data *	Nigel Metheringham	:	Better handling of timeouts of TCP conns *	Delian Delchev		:	Added support for ICMP requests and replys *	Nigel Metheringham	:	ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional *	Juan Jose Ciarlante	:	re-assign maddr if no packet received from outside *	Juan Jose Ciarlante	:	ported to 2.1 tree *	Juan Jose Ciarlante	:	reworked control connections *	Steven Clarke		:	Added Port Forwarding *	Juan Jose Ciarlante	:	Just ONE ip_masq_new (!) *	Juan Jose Ciarlante	:	IP masq modules support *	Juan Jose Ciarlante	:	don't go into search loop if mport specified *	Juan Jose Ciarlante	:	locking *	Steven Clarke		:	IP_MASQ_S_xx state design *	Juan Jose Ciarlante	:	IP_MASQ_S state implementation  *	Juan Jose Ciarlante	: 	xx_get() clears timer, _put() inserts it *	Juan Jose Ciarlante	: 	create /proc/net/ip_masq/  *	Juan Jose Ciarlante	: 	reworked checksums (save payload csum if possible) *	Juan Jose Ciarlante	: 	added missing ip_fw_masquerade checksum *	Juan Jose Ciarlante	: 	csum savings *	Juan Jose Ciarlante	: 	added user-space tunnel creation/del, etc *	Juan Jose Ciarlante	: 	(last) moved to ip_masq_user runtime module *	Juan Jose Ciarlante	: 	user timeout handling again *	Juan Jose Ciarlante	: 	make new modules support optional *	Juan Jose Ciarlante	: 	u-space context => locks reworked *	Juan Jose Ciarlante	: 	fixed stupid SMP locking bug *	Juan Jose Ciarlante	: 	fixed "tap"ing in demasq path by copy-on-w *	Juan Jose Ciarlante	: 	make masq_proto_doff() robust against fake sized/corrupted packets *	Kai Bankett		:	do not toss other IP protos in proto_doff() *	Dan Kegel		:	pointed correct NAT behavior for UDP streams *	Julian Anastasov	:	use daddr and dport as hash keys *	 */#include <linux/config.h>#include <linux/module.h>#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <linux/types.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/skbuff.h>#include <asm/system.h>#include <linux/stat.h>#include <linux/proc_fs.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/inet.h>#include <linux/init.h>#include <net/protocol.h>#include <net/icmp.h>#include <net/tcp.h>#include <net/udp.h>#include <net/checksum.h>#include <net/ip_masq.h>#ifdef CONFIG_IP_MASQUERADE_MOD#include <net/ip_masq_mod.h>#endif#include <linux/sysctl.h>#include <linux/ip_fw.h>#include <linux/ip_masq.h>int sysctl_ip_masq_debug = 0;/* *	Exported wrapper  */int ip_masq_get_debug_level(void){	return sysctl_ip_masq_debug;}struct ip_masq_hook *ip_masq_user_hook = NULL;/* *	Timeout table[state] *//* static int masq_timeout_table[IP_MASQ_S_LAST+1] = { */static struct ip_masq_timeout_table masq_timeout_table = {	ATOMIC_INIT(0),	/* refcnt */	0,		/* scale  */	{		30*60*HZ,	/*	IP_MASQ_S_NONE,	*/		15*60*HZ,	/*	IP_MASQ_S_ESTABLISHED,	*/		2*60*HZ,	/*	IP_MASQ_S_SYN_SENT,	*/		1*60*HZ,	/*	IP_MASQ_S_SYN_RECV,	*/		2*60*HZ,	/*	IP_MASQ_S_FIN_WAIT,	*/		2*60*HZ,	/*	IP_MASQ_S_TIME_WAIT,	*/		10*HZ,		/*	IP_MASQ_S_CLOSE,	*/		60*HZ,		/*	IP_MASQ_S_CLOSE_WAIT,	*/		30*HZ,		/*	IP_MASQ_S_LAST_ACK,	*/		2*60*HZ,	/*	IP_MASQ_S_LISTEN,	*/		5*60*HZ,	/*	IP_MASQ_S_UDP,	*/		1*60*HZ,	/*	IP_MASQ_S_ICMP,	*/		2*HZ,/*	IP_MASQ_S_LAST	*/	},	/* timeout */};#define MASQUERADE_EXPIRE_RETRY      masq_timeout_table.timeout[IP_MASQ_S_TIME_WAIT]static const char * state_name_table[IP_MASQ_S_LAST+1] = {	"NONE",		/*	IP_MASQ_S_NONE,	*/	"ESTABLISHED",	/*	IP_MASQ_S_ESTABLISHED,	*/	"SYN_SENT",	/*	IP_MASQ_S_SYN_SENT,	*/	"SYN_RECV",	/*	IP_MASQ_S_SYN_RECV,	*/	"FIN_WAIT",	/*	IP_MASQ_S_FIN_WAIT,	*/	"TIME_WAIT",	/*	IP_MASQ_S_TIME_WAIT,	*/	"CLOSE",	/*	IP_MASQ_S_CLOSE,	*/	"CLOSE_WAIT",	/*	IP_MASQ_S_CLOSE_WAIT,	*/	"LAST_ACK",	/*	IP_MASQ_S_LAST_ACK,	*/	"LISTEN",	/*	IP_MASQ_S_LISTEN,	*/	"UDP",		/*	IP_MASQ_S_UDP,	*/	"ICMP",		/*	IP_MASQ_S_ICMP,	*/	"BUG!",		/*	IP_MASQ_S_LAST	*/};#define mNO IP_MASQ_S_NONE#define mES IP_MASQ_S_ESTABLISHED#define mSS IP_MASQ_S_SYN_SENT#define mSR IP_MASQ_S_SYN_RECV#define mFW IP_MASQ_S_FIN_WAIT#define mTW IP_MASQ_S_TIME_WAIT#define mCL IP_MASQ_S_CLOSE#define mCW IP_MASQ_S_CLOSE_WAIT#define mLA IP_MASQ_S_LAST_ACK#define mLI IP_MASQ_S_LISTENstruct masq_tcp_states_t {	int next_state[IP_MASQ_S_LAST];	/* should be _LAST_TCP */};const char * ip_masq_state_name(int state){	if (state >= IP_MASQ_S_LAST)		return "ERR!";	return state_name_table[state];}struct masq_tcp_states_t masq_tcp_states [] = {/*	INPUT *//* 	  mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI 	*//*syn*/	{{mSR, mES, mES, mSR, mSR, mSR, mSR, mSR, mSR, mSR }},/*fin*/	{{mCL, mCW, mSS, mTW, mTW, mTW, mCL, mCW, mLA, mLI }},/*ack*/	{{mCL, mES, mSS, mSR, mFW, mTW, mCL, mCW, mCL, mLI }},/*rst*/ {{mCL, mCL, mCL, mSR, mCL, mCL, mCL, mCL, mLA, mLI }},/*	OUTPUT *//* 	  mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI 	*//*syn*/	{{mSS, mES, mSS, mES, mSS, mSS, mSS, mSS, mSS, mLI }},/*fin*/	{{mTW, mFW, mSS, mTW, mFW, mTW, mCL, mTW, mLA, mLI }},/*ack*/	{{mES, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mES }},/*rst*/ {{mCL, mCL, mSS, mCL, mCL, mTW, mCL, mCL, mCL, mCL }},};static __inline__ int masq_tcp_state_idx(struct tcphdr *th, int output) {	/*	 *	[0-3]: input states, [4-7]: output.	 */	if (output) 		output=4;	if (th->rst)		return output+3;	if (th->syn)		return output+0;	if (th->fin)		return output+1;	if (th->ack)		return output+2;	return -1;}static int masq_set_state_timeout(struct ip_masq *ms, int state){	struct ip_masq_timeout_table *mstim = ms->timeout_table;	int scale;	/*	 *	Use default timeout table if no specific for this entry	 */	if (!mstim) 		mstim = &masq_timeout_table;	ms->timeout = mstim->timeout[ms->state=state];	scale = mstim->scale;	if (scale<0)		ms->timeout >>= -scale;	else if (scale > 0)		ms->timeout <<= scale;	return state;}static int masq_tcp_state(struct ip_masq *ms, int output, struct tcphdr *th){	int state_idx;	int new_state = IP_MASQ_S_CLOSE;	if ((state_idx = masq_tcp_state_idx(th, output)) < 0) {		IP_MASQ_DEBUG(1, "masq_state_idx(%d)=%d!!!\n", 			output, state_idx);		goto tcp_state_out;	}	new_state = masq_tcp_states[state_idx].next_state[ms->state];	tcp_state_out:	if (new_state!=ms->state)		IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n",				masq_proto_name(ms->protocol),				output? "output" : "input ",				th->syn? 'S' : '.',				th->fin? 'F' : '.',				th->ack? 'A' : '.',				th->rst? 'R' : '.',				ntohl(ms->saddr), ntohs(ms->sport),				ntohl(ms->daddr), ntohs(ms->dport),				ip_masq_state_name(ms->state),				ip_masq_state_name(new_state));	return masq_set_state_timeout(ms, new_state);}/* *	Handle state transitions */static int masq_set_state(struct ip_masq *ms, int output, struct iphdr *iph, void *tp){	switch (iph->protocol) {		case IPPROTO_ICMP:			return masq_set_state_timeout(ms, IP_MASQ_S_ICMP);		case IPPROTO_UDP:			return masq_set_state_timeout(ms, IP_MASQ_S_UDP);		case IPPROTO_TCP:			return masq_tcp_state(ms, output, tp);	}	return -1;}/* *	Set LISTEN timeout. (ip_masq_put will setup timer) */int ip_masq_listen(struct ip_masq *ms){	masq_set_state_timeout(ms, IP_MASQ_S_LISTEN);	return ms->timeout;}/*  *	Dynamic address rewriting  */extern int sysctl_ip_dynaddr;/* *	Lookup lock */rwlock_t __ip_masq_lock = RW_LOCK_UNLOCKED;/* *	Implement IP packet masquerading *//* * Converts an ICMP reply code into the equivalent request code */static __inline__ const __u8 icmp_type_request(__u8 type){   switch (type)   {      case ICMP_ECHOREPLY: return ICMP_ECHO; break;      case ICMP_TIMESTAMPREPLY: return ICMP_TIMESTAMP; break;      case ICMP_INFO_REPLY: return ICMP_INFO_REQUEST; break;      case ICMP_ADDRESSREPLY: return ICMP_ADDRESS; break;      default: return (255); break;   }}/* * Helper macros - attempt to make code clearer!  *//* ID used in ICMP lookups */#define icmp_id(icmph)		((icmph->un).echo.id)/* (port) hash value using in ICMP lookups for requests */#define icmp_hv_req(icmph)	((__u16)(icmph->code+(__u16)(icmph->type<<8)))/* (port) hash value using in ICMP lookups for replies */#define icmp_hv_rep(icmph)	((__u16)(icmph->code+(__u16)(icmp_type_request(icmph->type)<<8)))/* *	Last masq_port number in use. *	Will cycle in MASQ_PORT boundaries. */static __u16 masq_port = PORT_MASQ_BEGIN;static spinlock_t masq_port_lock = SPIN_LOCK_UNLOCKED;/* *	free ports counters (UDP & TCP) * *	Their value is _less_ or _equal_ to actual free ports: *	same masq port, diff masq addr (firewall iface address) allocated *	entries are accounted but their actually don't eat a more than 1 port. * *	Greater values could lower MASQ_EXPIRATION setting as a way to *	manage 'masq_entries resource'. * *	By default we will reuse masq.port iff (output) connection *	(5-upla) if not duplicated.  *	This may break midentd and others ... */#ifdef CONFIG_IP_MASQ_NREUSE#define PORT_MASQ_MUL 1#else#define PORT_MASQ_MUL 10#endif/* *	At the moment, hardcore in sync with masq_proto_num */atomic_t ip_masq_free_ports[3] = {        ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */        ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */        ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* ICMP */};/* *	Counts entries that have been requested with specific mport. *	Used for incoming packets to "relax" input rule (port in MASQ range). */atomic_t mport_count = ATOMIC_INIT(0);EXPORT_SYMBOL(ip_masq_get_debug_level);EXPORT_SYMBOL(ip_masq_new);EXPORT_SYMBOL(ip_masq_listen);EXPORT_SYMBOL(ip_masq_free_ports);EXPORT_SYMBOL(ip_masq_out_get);EXPORT_SYMBOL(ip_masq_in_get);EXPORT_SYMBOL(ip_masq_put);EXPORT_SYMBOL(ip_masq_control_add);EXPORT_SYMBOL(ip_masq_control_del);EXPORT_SYMBOL(ip_masq_control_get);EXPORT_SYMBOL(ip_masq_user_hook);EXPORT_SYMBOL(ip_masq_state_name);EXPORT_SYMBOL(ip_masq_select_addr);EXPORT_SYMBOL(__ip_masq_lock);EXPORT_SYMBOL(ip_masq_m_table);EXPORT_SYMBOL(ip_masq_s_table);EXPORT_SYMBOL(ip_masq_d_table);/* *	3 ip_masq hash double linked tables:  *	  2 for input  m{addr,port}  and output s{addr,port} pkts lookups. *	  1 for extra modules support (daddr) */  #define IP_MASQ_NTABLES 3struct list_head ip_masq_m_table[IP_MASQ_TAB_SIZE];struct list_head ip_masq_s_table[IP_MASQ_TAB_SIZE];struct list_head ip_masq_d_table[IP_MASQ_TAB_SIZE];/* * timeouts */#if 000 /* FIXED timeout handling */static struct ip_fw_masq ip_masq_dummy = {	MASQUERADE_EXPIRE_TCP,	MASQUERADE_EXPIRE_TCP_FIN,	MASQUERADE_EXPIRE_UDP};EXPORT_SYMBOL(ip_masq_expire);struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;#endif/* *	These flags enable non-strict d{addr,port} checks *	Given that both (in/out) lookup tables are hashed *	by m{addr,port} and s{addr,port} this is quite easy  */#define MASQ_DADDR_PASS	(IP_MASQ_F_NO_DADDR|IP_MASQ_F_DLOOSE)#define MASQ_DPORT_PASS	(IP_MASQ_F_NO_DPORT|IP_MASQ_F_DLOOSE)/* *	By default enable dest loose semantics */#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1/* * 	Set masq expiration (deletion) and adds timer, *	if timeout==0 cancel expiration. *	Warning: it does not check/delete previous timer! */static void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout){        if (tout) {                ms->timer.expires = jiffies+tout;                add_timer(&ms->timer);        } else {                del_timer(&ms->timer);        }}/* *	Returns hash value */static __inline__ unsigned ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port){        return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1);}/* *	Hashes ip_masq by its proto,addrs,ports. *	should be called with locked tables. *	returns bool success. */static int ip_masq_hash(struct ip_masq *ms){        unsigned hash;        if (ms->flags & IP_MASQ_F_HASHED) {                IP_MASQ_ERR( "ip_masq_hash(): request for already hashed, called from %p\n",			__builtin_return_address(0));                return 0;        }	atomic_add(IP_MASQ_NTABLES, &ms->refcnt);	if ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |		IP_MASQ_F_SIMPLE_HASH)) == 0)		/*		 *	Hash by proto,m{addr,port},d{addr,port}		 */		hash = ip_masq_hash_key(ms->protocol,			ms->maddr^ms->daddr, ms->mport^ms->dport);	else		/*		 *	Hash by proto,m{addr,port}		 */		hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);	list_add(&ms->m_list, &ip_masq_m_table[hash]);	if ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |		IP_MASQ_F_NO_SADDR | IP_MASQ_F_NO_SPORT |		IP_MASQ_F_SIMPLE_HASH)) == 0)		/*		 *	Hash by proto,s{addr,port},d{addr,port}		 */		hash = ip_masq_hash_key(ms->protocol,			ms->saddr^ms->daddr, ms->sport^ms->dport);	else		/*		 *	Hash by proto,s{addr,port}		 */		hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);	list_add(&ms->s_list, &ip_masq_s_table[hash]);        /*         *	Hash by proto,d{addr,port}         */        hash = ip_masq_hash_key(ms->protocol, ms->daddr, ms->dport);	list_add(&ms->d_list, &ip_masq_d_table[hash]);        ms->flags |= IP_MASQ_F_HASHED;        return 1;}/* *	UNhashes ip_masq from ip_masq_[ms]_tables. *	should be called with locked tables. *	returns bool success. */

⌨️ 快捷键说明

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