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

📄 ip_nat_ftp.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
字号:
/* FTP extension for TCP NAT alteration. */#include <linux/module.h>#include <linux/netfilter_ipv4.h>#include <linux/ip.h>#include <linux/tcp.h>#include <net/tcp.h>#include <linux/netfilter_ipv4/ip_nat.h>#include <linux/netfilter_ipv4/ip_nat_helper.h>#include <linux/netfilter_ipv4/ip_nat_rule.h>#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>#include <linux/netfilter_ipv4/ip_conntrack_helper.h>#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endif#define MAX_PORTS 8static int ports[MAX_PORTS];static int ports_c = 0;#ifdef MODULE_PARMMODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");#endifDECLARE_LOCK_EXTERN(ip_ftp_lock);/* FIXME: Time out? --RR */static intftp_nat_expected(struct sk_buff **pskb,		 unsigned int hooknum,		 struct ip_conntrack *ct,		 struct ip_nat_info *info,		 struct ip_conntrack *master,		 struct ip_nat_info *masterinfo,		 unsigned int *verdict){	struct ip_nat_multi_range mr;	u_int32_t newdstip, newsrcip, newip;	struct ip_ct_ftp *ftpinfo;	IP_NF_ASSERT(info);	IP_NF_ASSERT(master);	IP_NF_ASSERT(masterinfo);	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));	DEBUGP("nat_expected: We have a connection!\n");	/* Master must be an ftp connection */	ftpinfo = &master->help.ct_ftp_info;	LOCK_BH(&ip_ftp_lock);	if (ftpinfo->is_ftp != IP_CONNTR_FTP) {		UNLOCK_BH(&ip_ftp_lock);		DEBUGP("nat_expected: master not ftp\n");		return 0;	}	if (ftpinfo->ftptype == IP_CT_FTP_PORT	    || ftpinfo->ftptype == IP_CT_FTP_EPRT) {		/* PORT command: make connection go to the client. */		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;		DEBUGP("nat_expected: PORT cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",		       NIPQUAD(newsrcip), NIPQUAD(newdstip));	} else {		/* PASV command: make the connection go to the server */		newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;		newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;		DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",		       NIPQUAD(newsrcip), NIPQUAD(newdstip));	}	UNLOCK_BH(&ip_ftp_lock);	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)		newip = newsrcip;	else		newip = newdstip;	DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));	mr.rangesize = 1;	/* We don't want to manip the per-protocol, just the IPs... */	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;	mr.range[0].min_ip = mr.range[0].max_ip = newip;	/* ... unless we're doing a MANIP_DST, in which case, make	   sure we map to the correct port */	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;		mr.range[0].min = mr.range[0].max			= ((union ip_conntrack_manip_proto)				{ htons(ftpinfo->port) });	}	*verdict = ip_nat_setup_info(ct, &mr, hooknum);	return 1;}static intmangle_rfc959_packet(struct sk_buff **pskb,		     u_int32_t newip,		     u_int16_t port,		     unsigned int matchoff,		     unsigned int matchlen,		     struct ip_conntrack *ct,		     enum ip_conntrack_info ctinfo){	char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];	MUST_BE_LOCKED(&ip_ftp_lock);	sprintf(buffer, "%u,%u,%u,%u,%u,%u",		NIPQUAD(newip), port>>8, port&0xFF);	DEBUGP("calling ip_nat_mangle_tcp_packet\n");	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 					matchlen, buffer, strlen(buffer));}/* |1|132.235.1.2|6275| */static intmangle_eprt_packet(struct sk_buff **pskb,		   u_int32_t newip,		   u_int16_t port,		   unsigned int matchoff,		   unsigned int matchlen,		   struct ip_conntrack *ct,		   enum ip_conntrack_info ctinfo){	char buffer[sizeof("|1|255.255.255.255|65535|")];	MUST_BE_LOCKED(&ip_ftp_lock);	sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);	DEBUGP("calling ip_nat_mangle_tcp_packet\n");	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 					matchlen, buffer, strlen(buffer));}/* |1|132.235.1.2|6275| */static intmangle_epsv_packet(struct sk_buff **pskb,		   u_int32_t newip,		   u_int16_t port,		   unsigned int matchoff,		   unsigned int matchlen,		   struct ip_conntrack *ct,		   enum ip_conntrack_info ctinfo){	char buffer[sizeof("|||65535|")];	MUST_BE_LOCKED(&ip_ftp_lock);	sprintf(buffer, "|||%u|", port);	DEBUGP("calling ip_nat_mangle_tcp_packet\n");	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, 					matchlen, buffer, strlen(buffer));}static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,		     unsigned int,		     unsigned int,		     struct ip_conntrack *,		     enum ip_conntrack_info)= { [IP_CT_FTP_PORT] mangle_rfc959_packet,    [IP_CT_FTP_PASV] mangle_rfc959_packet,    [IP_CT_FTP_EPRT] mangle_eprt_packet,    [IP_CT_FTP_EPSV] mangle_epsv_packet};static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,			  struct ip_conntrack *ct,			  unsigned int datalen,			  struct sk_buff **pskb,			  enum ip_conntrack_info ctinfo){	u_int32_t newip;	struct iphdr *iph = (*pskb)->nh.iph;	struct tcphdr *tcph = (void *)iph + iph->ihl*4;	u_int16_t port;	struct ip_conntrack_tuple tuple;	/* Don't care about source port */	const struct ip_conntrack_tuple mask		= { { 0xFFFFFFFF, { 0 } },		    { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };	memset(&tuple, 0, sizeof(tuple));	MUST_BE_LOCKED(&ip_ftp_lock);	DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n",	       ct_ftp_info->seq, ct_ftp_info->len,	       ntohl(tcph->seq), datalen);	/* Change address inside packet to match way we're mapping	   this connection. */	if (ct_ftp_info->ftptype == IP_CT_FTP_PASV	    || ct_ftp_info->ftptype == IP_CT_FTP_EPSV) {		/* PASV/EPSV response: must be where client thinks server		   is */		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;		/* Expect something from client->server */		tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;	} else {		/* PORT command: must be where server thinks client is */		newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;		/* Expect something from server->client */		tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;	}	tuple.dst.protonum = IPPROTO_TCP;	/* Try to get same port: if not, try to change it. */	for (port = ct_ftp_info->port; port != 0; port++) {		tuple.dst.u.tcp.port = htons(port);		if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)			break;	}	if (port == 0)		return 0;	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,					  ct_ftp_info->seq - ntohl(tcph->seq),					  ct_ftp_info->len, ct, ctinfo))		return 0;	return 1;}static unsigned int help(struct ip_conntrack *ct,			 struct ip_nat_info *info,			 enum ip_conntrack_info ctinfo,			 unsigned int hooknum,			 struct sk_buff **pskb){	struct iphdr *iph = (*pskb)->nh.iph;	struct tcphdr *tcph = (void *)iph + iph->ihl*4;	unsigned int datalen;	int dir;	int score;	struct ip_ct_ftp *ct_ftp_info		= &ct->help.ct_ftp_info;	/* Delete SACK_OK on initial TCP SYNs. */	if (tcph->syn && !tcph->ack)		ip_nat_delete_sack(*pskb, tcph);	/* Only mangle things once: original direction in POST_ROUTING	   and reply direction on PRE_ROUTING. */	dir = CTINFO2DIR(ctinfo);	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {		DEBUGP("nat_ftp: Not touching dir %s at hook %s\n",		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");		return NF_ACCEPT;	}	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;	score = 0;	LOCK_BH(&ip_ftp_lock);	if (ct_ftp_info->len) {		/* If it's in the right range... */		score += between(ct_ftp_info->seq, ntohl(tcph->seq),				 ntohl(tcph->seq) + datalen);		score += between(ct_ftp_info->seq + ct_ftp_info->len,				 ntohl(tcph->seq),				 ntohl(tcph->seq) + datalen);		if (score == 1) {			/* Half a match?  This means a partial retransmisison.			   It's a cracker being funky. */			if (net_ratelimit()) {				printk("FTP_NAT: partial packet %u/%u in %u/%u\n",				       ct_ftp_info->seq, ct_ftp_info->len,				       ntohl(tcph->seq),				       ntohl(tcph->seq) + datalen);			}			UNLOCK_BH(&ip_ftp_lock);			return NF_DROP;		} else if (score == 2) {			if (!ftp_data_fixup(ct_ftp_info, ct, datalen,					    pskb, ctinfo)) {				UNLOCK_BH(&ip_ftp_lock);				return NF_DROP;			}			/* skb may have been reallocated */			iph = (*pskb)->nh.iph;			tcph = (void *)iph + iph->ihl*4;		}	}	UNLOCK_BH(&ip_ftp_lock);	ip_nat_seq_adjust(*pskb, ct, ctinfo);	return NF_ACCEPT;}static struct ip_nat_helper ftp[MAX_PORTS];static char ftp_names[MAX_PORTS][6];static struct ip_nat_expect ftp_expect= { { NULL, NULL }, ftp_nat_expected };/* Not __exit: called from init() */static void fini(void){	int i;	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);		ip_nat_helper_unregister(&ftp[i]);	}	ip_nat_expect_unregister(&ftp_expect);}static int __init init(void){	int i, ret;	char *tmpname;	ret = ip_nat_expect_register(&ftp_expect);	if (ret == 0) {		if (ports[0] == 0)			ports[0] = 21;		for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {			memset(&ftp[i], 0, sizeof(struct ip_nat_helper));			ftp[i].tuple.dst.protonum = IPPROTO_TCP;			ftp[i].tuple.src.u.tcp.port = htons(ports[i]);			ftp[i].mask.dst.protonum = 0xFFFF;			ftp[i].mask.src.u.tcp.port = 0xFFFF;			ftp[i].help = help;			tmpname = &ftp_names[i][0];			sprintf(tmpname, "ftp%2.2d", i);			ftp[i].name = tmpname;			DEBUGP("ip_nat_ftp: Trying to register for port %d\n",					ports[i]);			ret = ip_nat_helper_register(&ftp[i]);			if (ret) {				printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);				fini();				return ret;			}			ports_c++;		}	} else {		ip_nat_expect_unregister(&ftp_expect);	}	return ret;}module_init(init);module_exit(fini);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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