patch-2.4.20 linux-2.4.20/net/ipv4/netfilter/ip_nat_ftp.c

Next file: linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c
Previous file: linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.20/net/ipv4/netfilter/ip_nat_ftp.c
@@ -28,38 +28,30 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 ftp_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_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_ftp *ftpinfo;
+	struct ip_ct_ftp_expect *exp_ftp_info;
 
+	struct ip_conntrack *master = master_ct(ct);
+	
 	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;
+	exp_ftp_info = &ct->master->help.exp_ftp_info;
 
 	LOCK_BH(&ip_ftp_lock);
-	if (ftpinfo->is_ftp != 21) {
-		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) {
+	if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
+	    || exp_ftp_info->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;
@@ -92,11 +84,9 @@
 		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) });
+				{ htons(exp_ftp_info->port) });
 	}
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
 static int
@@ -176,27 +166,22 @@
     [IP_CT_FTP_EPSV] mangle_epsv_packet
 };
 
-static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
+static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	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 } };
+	struct ip_conntrack_tuple newtuple;
 
-	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);
+	DEBUGP("FTP_NAT: seq %u + %u in %u\n",
+	       expect->seq, ct_ftp_info->len,
+	       ntohl(tcph->seq));
 
 	/* Change address inside packet to match way we're mapping
 	   this connection. */
@@ -206,29 +191,34 @@
 		   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;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+		newtuple.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;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 	}
-	tuple.dst.protonum = IPPROTO_TCP;
+	newtuple.dst.protonum = IPPROTO_TCP;
+	newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
 
 	/* 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);
+		newtuple.dst.u.tcp.port = htons(port);
 
-		if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
+		if (ip_conntrack_change_expect(expect, &newtuple) == 0)
 			break;
 	}
 	if (port == 0)
 		return 0;
 
 	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
-					  ct_ftp_info->seq - ntohl(tcph->seq),
+					  expect->seq - ntohl(tcph->seq),
 					  ct_ftp_info->len, ct, ctinfo))
 		return 0;
 
@@ -236,6 +226,7 @@
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int hooknum,
@@ -245,13 +236,12 @@
 	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);
+	struct ip_ct_ftp_expect *ct_ftp_info;
+
+	if (!exp)
+		DEBUGP("ip_nat_ftp: no exp!!");
+
+	ct_ftp_info = &exp->help.exp_ftp_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -267,103 +257,87 @@
 	}
 
 	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);
-			}
+	/* If it's in the right range... */
+	if (between(exp->seq + ct_ftp_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
 			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;
 		}
+	} else {
+		/* 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",
+			       exp->seq, ct_ftp_info->len,
+			       ntohl(tcph->seq),
+			       ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_ftp_lock);
+		return NF_DROP;
 	}
-
 	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 };
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
 {
 	int i;
 
-	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+	for (i = 0; i < ports_c; 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;
+	int i, ret = 0;
 	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++;
-		}
+	if (ports[0] == 0)
+		ports[0] = FTP_PORT;
 
-	} else {
-		ip_nat_expect_unregister(&ftp_expect);
+	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;
+		ftp[i].me = THIS_MODULE;
+		ftp[i].flags = 0;
+		ftp[i].expect = ftp_nat_expected;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", 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++;
 	}
+
 	return ret;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)