;; FTP EPRT command support patch for libalias
;; Oct 13, 1999 by Hajimu UMEMOTO <ume@mahoroba.org>
;;
;; This patch supports IPv4 of FTP EPRT command to libalias.  The EPRT
;; command is described in RFC2428 - FTP Extensions for IPv6 and NATs.
;; This patch is for FreeBSD 3.3-RELEASE's alias_ftp.c.  But, it is
;; also applicable to FreeBSD 2.2.8-RELEASE or today of 4.0-CURRENT.
;;
--- lib/libalias/alias_ftp.c.orig	Sat Jul  3 17:29:03 1999
+++ lib/libalias/alias_ftp.c	Wed Oct 13 19:34:42 1999
@@ -48,7 +48,9 @@
 
 #include "alias_local.h"
 
-static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int);
+static int  ParseFtpPortCommand(char *, int, struct ip *, struct alias_link *, int);
+static void ParseFtpEprtCommand(char *, int, struct ip *, struct alias_link *, int);
+static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int, int);
 
 
 
@@ -59,8 +61,6 @@
 int maxpacketsize  /* The maximum size this packet can grow to (including headers) */)
 {
     int hlen, tlen, dlen;
-    struct in_addr true_addr;
-    u_short true_port;
     char *sptr;
     struct tcphdr *tc;
         
@@ -79,58 +79,152 @@
     sptr += hlen;
 
 /* Parse through string using state diagram method */
+    if (!ParseFtpPortCommand(sptr, dlen, pip, link, maxpacketsize))
+	ParseFtpEprtCommand(sptr, dlen, pip, link, maxpacketsize);
+}
+
+static int
+ParseFtpPortCommand(
+char *sptr,
+int dlen,
+struct ip *pip,	  /* IP packet to examine/patch */
+struct alias_link *link, /* The link to go through (aliased port) */
+int maxpacketsize  /* The maximum size this packet can grow to (including headers) */)
+{
+    struct in_addr true_addr;
+    u_short true_port;
+    char ch, zero;
+    int i, state;
+    u_long a1, a2, a3, a4;
+    u_short p1, p2; 
+
+    a1=0; a2=0; a3=0; a4=0; p1=0; p2=0;
+    zero = '0';
+    state=-4;
+    for (i=0; i<dlen; i++)
     {
-        char ch, zero;
-        int i, state;
-        u_long a1, a2, a3, a4;
-        u_short p1, p2; 
-
-        a1=0; a2=0; a3=0; a4=0; p1=0; p2=0;
-        zero = '0';
-        state=-4;
-        for (i=0; i<dlen; i++)
-        {
-            ch = sptr[i];
-            switch (state)
-            {
-                case -4: if (ch == 'P') state=-3; else return; break;
-                case -3: if (ch == 'O') state=-2; else return; break;
-                case -2: if (ch == 'R') state=-1; else return; break;
-                case -1: if (ch == 'T') state= 0; else return; break;
-
-                case 0 :
-                    if (isdigit(ch)) {a1=ch-zero; state=1 ;} break;
-                case 1 :
-                    if (isdigit(ch)) a1=10*a1+ch-zero; else state=2 ; break;
-                case 2 :
-                    if (isdigit(ch)) {a2=ch-zero; state=3 ;} break;
-                case 3 :
-                    if (isdigit(ch)) a2=10*a2+ch-zero; else state=4 ; break;
-                case 4 :
-                    if (isdigit(ch)) {a3=ch-zero; state=5 ;} break;
-                case 5 :
-                    if (isdigit(ch)) a3=10*a3+ch-zero; else state=6 ; break;
-                case 6 :
-                    if (isdigit(ch)) {a4=ch-zero; state=7 ;} break;
-                case 7 :
-                    if (isdigit(ch)) a4=10*a4+ch-zero; else state=8 ; break;
-                case 8 :
-                    if (isdigit(ch)) {p1=ch-zero; state=9 ;} break;
-                case 9 :
-                    if (isdigit(ch)) p1=10*p1+ch-zero; else state=10; break;
-                case 10:
-                    if (isdigit(ch)) {p2=ch-zero; state=11;} break;
-                case 11:
-                    if (isdigit(ch)) p2=10*p2+ch-zero; break;
-            }
-        }
+	ch = sptr[i];
+	switch (state)
+	{
+	case -4: if (ch == 'P') state=-3; else return 0; break;
+	case -3: if (ch == 'O') state=-2; else return 0; break;
+	case -2: if (ch == 'R') state=-1; else return 0; break;
+	case -1: if (ch == 'T') state= 0; else return 0; break;
+
+	case 0 :
+	    if (isdigit(ch)) {a1=ch-zero; state=1 ;} break;
+	case 1 :
+	    if (isdigit(ch)) a1=10*a1+ch-zero; else state=2 ; break;
+	case 2 :
+	    if (isdigit(ch)) {a2=ch-zero; state=3 ;} break;
+	case 3 :
+	    if (isdigit(ch)) a2=10*a2+ch-zero; else state=4 ; break;
+	case 4 :
+	    if (isdigit(ch)) {a3=ch-zero; state=5 ;} break;
+	case 5 :
+	    if (isdigit(ch)) a3=10*a3+ch-zero; else state=6 ; break;
+	case 6 :
+	    if (isdigit(ch)) {a4=ch-zero; state=7 ;} break;
+	case 7 :
+	    if (isdigit(ch)) a4=10*a4+ch-zero; else state=8 ; break;
+	case 8 :
+	    if (isdigit(ch)) {p1=ch-zero; state=9 ;} break;
+	case 9 :
+	    if (isdigit(ch)) p1=10*p1+ch-zero; else state=10; break;
+	case 10:
+	    if (isdigit(ch)) {p2=ch-zero; state=11;} break;
+	case 11:
+	    if (isdigit(ch)) p2=10*p2+ch-zero; break;
+	}
+    }
 
-        if (state == 11)
-        {
-            true_port = htons((p1<<8) + p2);
-            true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4);
-            NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize);
-        }
+    if (state == 11)
+    {
+	true_port = htons((p1<<8) + p2);
+	true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4);
+	NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize, 0);
+    }
+    return 1;
+}
+
+static void
+ParseFtpEprtCommand(
+char *sptr,
+int dlen,
+struct ip *pip,	  /* IP packet to examine/patch */
+struct alias_link *link, /* The link to go through (aliased port) */
+int maxpacketsize  /* The maximum size this packet can grow to (including headers) */)
+{
+    struct in_addr true_addr;
+    u_short true_port;
+    char ch, zero, delim;
+    int i, state;
+    u_long a1, a2, a3, a4;
+    u_short pt;
+
+    a1=0; a2=0; a3=0; a4=0; pt=0;
+    zero = '0';
+    delim='|';
+    state=-4;
+    for (i=0; i<dlen; i++)
+    {
+	ch = sptr[i];
+	switch (state)
+	{
+	case -4: if (ch == 'E') state=-3; else return; break;
+	case -3: if (ch == 'P') state=-2; else return; break;
+	case -2: if (ch == 'R') state=-1; else return; break;
+	case -1: if (ch == 'T') state= 0; else return; break;
+
+	case 0 :
+	    if (!isspace(ch)) {delim=ch; state=1 ;} break;
+	case 1 :
+	    if (ch=='1') state=2 ; else return; break;
+	case 2 :
+	    if (ch==delim) state=3 ; else return; break;
+	case 3 :
+	    if (isdigit(ch)) {a1=ch-zero; state=4 ;} else return; break;
+	case 4 :
+	    if (isdigit(ch)) a1=10*a1+ch-zero;
+	    else if (ch=='.') state=5 ;
+	    else return;
+	    break;
+	case 5 :
+	    if (isdigit(ch)) {a2=ch-zero; state=6 ;} else return; break;
+	case 6 :
+	    if (isdigit(ch)) a2=10*a2+ch-zero;
+	    else if (ch=='.') state=7 ;
+	    else return;
+	    break;
+	case 7:
+	    if (isdigit(ch)) {a3=ch-zero; state=8 ;} else return; break;
+	case 8 :
+	    if (isdigit(ch)) a3=10*a3+ch-zero;
+	    else if (ch=='.') state=9 ;
+	    else return;
+	    break;
+	case 9 :
+	    if (isdigit(ch)) {a4=ch-zero; state=10;} else return; break;
+	case 10:
+	    if (isdigit(ch)) a4=10*a4+ch-zero;
+	    else if (ch==delim) state=11;
+	    else return;
+	    break;
+	case 11:
+	    if (isdigit(ch)) {pt=ch-zero; state=12;} else return; break;
+	case 12:
+	    if (isdigit(ch)) pt=10*pt+ch-zero;
+	    else if (ch==delim) state=13;
+	    else return;
+	    break;
+	}
+    }
+
+    if (state == 13)
+    {
+	true_port = htons(pt);
+	true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4);
+	NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize, 1);
     }
 }
 
@@ -139,7 +233,8 @@
                   struct alias_link *link,
                   struct in_addr true_addr,
                   u_short true_port,
-                  int maxpacketsize)
+                  int maxpacketsize,
+                  int is_eprt)
 { 
     struct alias_link *ftp_link;
 
@@ -177,14 +272,21 @@
             ptr = (u_char *) &alias_address.s_addr;
             a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr;
 
+	    alias_port = GetAliasPort(ftp_link);
+
+	    if (is_eprt) {
+/* Generate command string */
+		sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n",
+			a1,a2,a3,a4,ntohs(alias_port));
+	    } else {
 /* Decompose alias port into pair format */
-            alias_port = GetAliasPort(ftp_link);
-            ptr = (char *) &alias_port;
-            p1 = *ptr++; p2=*ptr;
+		ptr = (char *) &alias_port;
+		p1 = *ptr++; p2=*ptr;
 
 /* Generate command string */
-            sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
-                     a1,a2,a3,a4,p1,p2);
+		sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
+			a1,a2,a3,a4,p1,p2);
+	    }
 
 /* Save string length for IP header modification */
             slen = strlen(stemp);

