svn commit: r223437 - head/sys/netinet/libalias

Andrey V. Elsukov ae at FreeBSD.org
Wed Jun 22 20:00:28 UTC 2011


Author: ae
Date: Wed Jun 22 20:00:27 2011
New Revision: 223437
URL: http://svn.freebsd.org/changeset/base/223437

Log:
  Export AddLink() function from libalias.  It can be used when custom
  alias address needs to be specified.
  Add inbound handler to the alias_ftp module. It helps handle active
  FTP transfer mode for the case with external clients and FTP server behind
  NAT. Fix passive FTP transfer case for server behind NAT using redirect with
  external IP address different from NAT ip address.
  
  PR:		kern/157957
  Submitted by:	Alexander V. Chernikov

Modified:
  head/sys/netinet/libalias/alias_db.c
  head/sys/netinet/libalias/alias_ftp.c
  head/sys/netinet/libalias/alias_local.h
  head/sys/netinet/libalias/libalias.3

Modified: head/sys/netinet/libalias/alias_db.c
==============================================================================
--- head/sys/netinet/libalias/alias_db.c	Wed Jun 22 19:47:45 2011	(r223436)
+++ head/sys/netinet/libalias/alias_db.c	Wed Jun 22 20:00:27 2011	(r223437)
@@ -552,10 +552,6 @@ static void	IncrementalCleanup(struct li
 static void	DeleteLink(struct alias_link *);
 
 static struct alias_link *
-AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
-    u_short, u_short, int, int);
-
-static struct alias_link *
 ReLink(struct alias_link *,
     struct in_addr, struct in_addr, struct in_addr,
     u_short, u_short, int, int);
@@ -572,9 +568,6 @@ static struct alias_link *
 #define ALIAS_PORT_MASK_EVEN       0x07ffe
 #define GET_NEW_PORT_MAX_ATTEMPTS       20
 
-#define GET_ALIAS_PORT                  -1
-#define GET_ALIAS_ID        GET_ALIAS_PORT
-
 #define FIND_EVEN_ALIAS_BASE             1
 
 /* GetNewPort() allocates port numbers.  Note that if a port number
@@ -937,17 +930,12 @@ DeleteLink(struct alias_link *lnk)
 }
 
 
-static struct alias_link *
-AddLink(struct libalias *la, struct in_addr src_addr,
-    struct in_addr dst_addr,
-    struct in_addr alias_addr,
-    u_short src_port,
-    u_short dst_port,
-    int alias_port_param,	/* if less than zero, alias   */
-    int link_type)
-{				/* port will be automatically *//* chosen.
-				 * If greater than    */
-	u_int start_point;	/* zero, equal to alias port  */
+struct alias_link *
+AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
+    struct in_addr alias_addr, u_short src_port, u_short dst_port,
+    int alias_port_param, int link_type)
+{
+	u_int start_point;
 	struct alias_link *lnk;
 
 	LIBALIAS_LOCK_ASSERT(la);

Modified: head/sys/netinet/libalias/alias_ftp.c
==============================================================================
--- head/sys/netinet/libalias/alias_ftp.c	Wed Jun 22 19:47:45 2011	(r223436)
+++ head/sys/netinet/libalias/alias_ftp.c	Wed Jun 22 20:00:27 2011	(r223437)
@@ -100,38 +100,68 @@ __FBSDID("$FreeBSD$");
 #define FTP_CONTROL_PORT_NUMBER 21
 
 static void
-AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *,	
-		  int maxpacketsize);
+AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *,
+    int maxpacketsize);
+static void
+AliasHandleFtpIn(struct libalias *, struct ip *, struct alias_link *);
 
-static int 
-fingerprint(struct libalias *la, struct alias_data *ah)
+static int
+fingerprint_out(struct libalias *la, struct alias_data *ah)
 {
 
-	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL || 
-		ah->maxpktsize == 0)
+	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
+	    ah->maxpktsize == 0)
 		return (-1);
-	if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER
-	    || ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
+	if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER ||
+	    ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
 		return (0);
 	return (-1);
 }
 
-static int 
-protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
+static int
+fingerprint_in(struct libalias *la, struct alias_data *ah)
+{
+
+	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL)
+		return (-1);
+	if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER ||
+	    ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
+		return (0);
+	return (-1);
+}
+
+static int
+protohandler_out(struct libalias *la, struct ip *pip, struct alias_data *ah)
 {
-	
+
 	AliasHandleFtpOut(la, pip, ah->lnk, ah->maxpktsize);
 	return (0);
 }
 
+
+static int
+protohandler_in(struct libalias *la, struct ip *pip, struct alias_data *ah)
+{
+
+	AliasHandleFtpIn(la, pip, ah->lnk);
+	return (0);
+}
+
 struct proto_handler handlers[] = {
-	{ 
-	  .pri = 80, 
-	  .dir = OUT, 
-	  .proto = TCP, 
-	  .fingerprint = &fingerprint, 
-	  .protohandler = &protohandler
-	}, 
+	{
+	  .pri = 80,
+	  .dir = OUT,
+	  .proto = TCP,
+	  .fingerprint = &fingerprint_out,
+	  .protohandler = &protohandler_out
+	},
+	{
+	  .pri = 80,
+	  .dir = IN,
+	  .proto = TCP,
+	  .fingerprint = &fingerprint_in,
+	  .protohandler = &protohandler_in
+	},
 	{ EOH }
 };
 
@@ -256,6 +286,57 @@ AliasHandleFtpOut(
 	}
 }
 
+static void
+AliasHandleFtpIn(struct libalias *la,
+    struct ip *pip,		/* IP packet to examine/patch */
+    struct alias_link *lnk)	/* The link to go through (aliased port) */
+{
+	int hlen, tlen, dlen, pflags;
+	char *sptr;
+	struct tcphdr *tc;
+
+	/* Calculate data length of TCP packet */
+	tc = (struct tcphdr *)ip_next(pip);
+	hlen = (pip->ip_hl + tc->th_off) << 2;
+	tlen = ntohs(pip->ip_len);
+	dlen = tlen - hlen;
+
+	/* Place string pointer and beginning of data */
+	sptr = (char *)pip;
+	sptr += hlen;
+
+	/*
+	 * Check that data length is not too long and previous message was
+	 * properly terminated with CRLF.
+	 */
+	pflags = GetProtocolFlags(lnk);
+	if (dlen <= MAX_MESSAGE_SIZE && (pflags & WAIT_CRLF) == 0 &&
+	    ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER &&
+	    (ParseFtpPortCommand(la, sptr, dlen) != 0 ||
+	     ParseFtpEprtCommand(la, sptr, dlen) != 0)) {
+		/*
+		 * Alias active mode client requesting data from server
+		 * behind NAT.  We need to alias server->client connection
+		 * to external address client is connecting to.
+		 */
+		AddLink(la, GetOriginalAddress(lnk), la->true_addr,
+		    GetAliasAddress(lnk), htons(FTP_CONTROL_PORT_NUMBER - 1),
+		    htons(la->true_port), GET_ALIAS_PORT, IPPROTO_TCP);
+	}
+	/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
+	if (dlen) {
+		sptr = (char *)pip;		/* start over at beginning */
+		tlen = ntohs(pip->ip_len);	/* recalc tlen, pkt may
+						 * have grown.
+						 */
+		if (sptr[tlen - 2] == '\r' && sptr[tlen - 1] == '\n')
+			pflags &= ~WAIT_CRLF;
+		else
+			pflags |= WAIT_CRLF;
+		SetProtocolFlags(lnk, pflags);
+       }
+}
+
 static int
 ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen)
 {
@@ -576,9 +657,10 @@ NewFtpMessage(struct libalias *la, struc
 	if (la->true_port < IPPORT_RESERVED)
 		return;
 
-/* Establish link to address and port found in FTP control message. */
-	ftp_lnk = FindUdpTcpOut(la, la->true_addr, GetDestAddress(lnk),
-	    htons(la->true_port), 0, IPPROTO_TCP, 1);
+	/* Establish link to address and port found in FTP control message. */
+	ftp_lnk = AddLink(la, la->true_addr, GetDestAddress(lnk),
+	    GetAliasAddress(lnk), htons(la->true_port), 0, GET_ALIAS_PORT,
+	    IPPROTO_TCP);
 
 	if (ftp_lnk != NULL) {
 		int slen, hlen, tlen, dlen;

Modified: head/sys/netinet/libalias/alias_local.h
==============================================================================
--- head/sys/netinet/libalias/alias_local.h	Wed Jun 22 19:47:45 2011	(r223436)
+++ head/sys/netinet/libalias/alias_local.h	Wed Jun 22 20:00:27 2011	(r223437)
@@ -67,6 +67,9 @@
 #define LINK_TABLE_OUT_SIZE        4001
 #define LINK_TABLE_IN_SIZE         4001
 
+#define	GET_ALIAS_PORT		-1
+#define	GET_ALIAS_ID		GET_ALIAS_PORT
+
 struct proxy_entry;
 
 struct libalias {
@@ -249,6 +252,10 @@ DifferentialChecksum(u_short * _cksum, v
 
 /* Internal data access */
 struct alias_link *
+AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
+    struct in_addr alias_addr, u_short src_port, u_short dst_port,
+    int alias_param, int link_type);
+struct alias_link *
 FindIcmpIn(struct libalias *la, struct in_addr _dst_addr, struct in_addr _alias_addr,
     u_short _id_alias, int _create);
 struct alias_link *

Modified: head/sys/netinet/libalias/libalias.3
==============================================================================
--- head/sys/netinet/libalias/libalias.3	Wed Jun 22 19:47:45 2011	(r223436)
+++ head/sys/netinet/libalias/libalias.3	Wed Jun 22 20:00:27 2011	(r223437)
@@ -824,6 +824,17 @@ argument is the pointer to a header frag
 is the pointer to the packet to be de-aliased.
 .Ed
 .Sh MISCELLANEOUS FUNCTIONS
+.Ft struct alias_link *
+.Fn AddLink "struct libalias *" "struct in_addr src_addr" "struct in_addr dst_addr" \
+"struct in_addr alias_addr" "u_short src_port" "u_short dst_port" \
+"int alias_param" "int link_type"
+.Bd -ragged -offset indent
+This function adds new state to instance hash table.
+Zero can be specified instead of dst_address and/or dst port.
+This makes link partially specified dynamic.
+However due to hashing method such links can be resolved on inbound (ext -> int) only.
+.Ed
+.Pp
 .Ft void
 .Fn LibAliasSetTarget "struct libalias *" "struct in_addr addr"
 .Bd -ragged -offset indent


More information about the svn-src-all mailing list