diff -aurN usr.sbin.original/ppp/chap.c usr.sbin/ppp/chap.c
--- usr.sbin.original/ppp/chap.c	Sun May 12 05:48:16 1996
+++ usr.sbin/ppp/chap.c	Mon Oct 14 22:24:57 1996
@@ -147,7 +147,7 @@
     }
     name = VarAuthName;
     namelen = strlen(VarAuthName);
-    argp = malloc(1 + valsize + namelen);
+    argp = malloc(1 + valsize + namelen + 16);
     digest = argp;
     *digest++ = 16;		/* value size */
     ap = answer;
@@ -169,6 +169,7 @@
     ap += namelen;
     /* Send answer to the peer */
     ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
+    free(argp);
     break;
   case CHAP_RESPONSE:
     if (keyp) {
diff -aurN usr.sbin.original/ppp/command.c usr.sbin/ppp/command.c
--- usr.sbin.original/ppp/command.c	Sun Oct  6 22:32:27 1996
+++ usr.sbin/ppp/command.c	Mon Oct 14 22:24:57 1996
@@ -470,16 +470,20 @@
   return(val);
 }
 
+int aft_cmd = 1;
+
 void
-Prompt(flag)
-int flag;
+Prompt()
 {
   char *pconnect, *pauth;
 
   if (!(mode & MODE_INTER))
     return;
 
-  if (flag) printf("\n");
+  if (!aft_cmd)
+    printf("\n");
+  else
+    aft_cmd = 0;
 
   if ( VarLocalAuth == LOCAL_AUTH )
     pauth = " ON ";
@@ -968,6 +972,8 @@
 	"Set escape characters", "hex-digit ..."},
   { "ifaddr",   NULL,   SetInterfaceAddr,	LOCAL_AUTH,
 	"Set destination address", "[src-addr [dst-addr [netmask [trg-addr]]]]"},
+  { "taddr",    NULL,   SetTranslationAddr,	LOCAL_AUTH,
+	"Set translation address", "translation-addr"},
   { "ifilter",  NULL,     SetIfilter, 		LOCAL_AUTH,
 	"Set input filter", "..."},
   { "login",    NULL,     SetVariable,		LOCAL_AUTH,
@@ -1012,6 +1018,29 @@
   else
     printf("Use `set ?' to get a list or `set ? <var>' for syntax help.\n");
   return(val);
+}
+
+/* Set IP address should be translate. (NAT) */
+static int
+SetTranslationAddr(list, argc, argv)
+struct cmdtab *list;
+int argc;
+char **argv;
+{
+    DefTransAddress.ipaddr.s_addr = 0xffffffff;
+    if (argc > 0) {
+	ParseAddr(argc, argv++, &DefTransAddress.ipaddr, 
+		  &DefTransAddress.mask, &DefTransAddress.width);
+    }
+    /*
+     *  0.0.0.0 and 255.255.255.255 means no translation
+     */
+    if (DefTransAddress.ipaddr.s_addr == 0xffffffff || 
+	DefTransAddress.ipaddr.s_addr == 0) {
+	DefTransAddress.mask.s_addr = 0xffffffff;
+	DefTransAddress.width = 32;
+    }
+    return(1);
 }
 
 
diff -aurN usr.sbin.original/ppp/filter.c usr.sbin/ppp/filter.c
--- usr.sbin.original/ppp/filter.c	Thu Jan 11 06:27:43 1996
+++ usr.sbin/ppp/filter.c	Mon Oct 14 22:22:17 1996
@@ -238,13 +238,23 @@
     if (argc == 0)
       return(1);
   }
-  if (argc == 1) {
-    if (STREQ(*argv, "estab")) {
-      filterdata.opt.estab = 1;
+  if (argc >= 1 && STREQ(*argv, "estab")) {
+    filterdata.opt.estab = 1;
+    argc -= 1; argv += 1;
+    if (argc == 0)
+      return(1);
+  }
+  if (argc >= 1 && STREQ(*argv, "syn")) {
+    filterdata.opt.syn = 1;
+    argc -= 1; argv += 1;
+    if (argc == 0)
+      return(1);
+  }
+  if (argc >= 1 && STREQ(*argv, "finrst")) {
+    filterdata.opt.finrst = 1;
+    /* argc -= 1; argv += 1; */
+    if (argc == 0)
       return(1);
-    }
-    printf("estab is expected: %s\n", *argv);
-    return(0);
   }
   if (argc > 0)
     printf("bad src/dst port syntax: %s\n", *argv);
@@ -359,6 +369,8 @@
   printf("src:  %s (%d)\n", opname[fp->opt.srcop], fp->opt.srcport);
   printf("dst:  %s (%d)\n", opname[fp->opt.dstop], fp->opt.dstport);
   printf("estab: %d\n", fp->opt.estab);
+  printf("syn: %d\n", fp->opt.syn);
+  printf("finrst: %d\n", fp->opt.finrst);
 #endif
 
   if (val)
@@ -448,6 +460,10 @@
 	  printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport);
 	if (fp->opt.estab)
 	  printf(" estab");
+	if (fp->opt.syn)
+	  printf(" syn");
+	if (fp->opt.finrst)
+	  printf(" finrst");
 
       }
       printf("\n");
diff -aurN usr.sbin.original/ppp/filter.h usr.sbin/ppp/filter.h
--- usr.sbin.original/ppp/filter.h	Fri Jan 12 02:48:43 1996
+++ usr.sbin/ppp/filter.h	Mon Oct 14 22:22:17 1996
@@ -65,6 +65,8 @@
     short   dstop;
     u_short dstport;
     int     estab;
+    int     syn;
+    int     finrst;
   } opt;
 };
 
diff -aurN usr.sbin.original/ppp/ip.c usr.sbin/ppp/ip.c
--- usr.sbin.original/ppp/ip.c	Sun May 12 05:48:25 1996
+++ usr.sbin/ppp/ip.c	Mon Oct 14 22:23:33 1996
@@ -37,6 +37,8 @@
 
 extern void SendPppFrame();
 extern void LcpClose();
+extern int CheckTrans();
+extern void ChangeDestIPAddress();
 
 static struct pppTimer IdleTimer;
 
@@ -120,7 +122,7 @@
 int direction;
 {
   struct filterent *fp = Filters[direction];
-  int gotinfo, cproto, estab, n;
+  int gotinfo, cproto, estab, syn, finrst, n;
   struct tcphdr *th;
   struct udphdr *uh;
   struct icmp *ih;
@@ -128,7 +130,7 @@
   u_short sport, dport;
 
   if (fp->action) {
-    cproto = gotinfo = estab = 0;
+    cproto = gotinfo = estab = syn = finrst = 0;
     sport = dport = 0;
     for (n = 0; n < MAXFILTERS; n++) {
       if (fp->action) {
@@ -149,17 +151,19 @@
 	      switch (pip->ip_p) {
 	      case IPPROTO_ICMP:
 		cproto = P_ICMP; ih = (struct icmp *)ptop;
-		sport = ih->icmp_type; estab = 1;
+		sport = ih->icmp_type; estab = syn = finrst = 1;
 		break;
 	      case IPPROTO_UDP:
 		cproto = P_UDP; uh = (struct udphdr *)ptop;
 		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
-		estab = 1;
+		estab = syn = finrst = 1;
 		break;
 	      case IPPROTO_TCP:
 		cproto = P_TCP; th = (struct tcphdr *)ptop;
 		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
 		estab = (th->th_flags & TH_ACK);
+		syn = (th->th_flags & TH_SYN);
+		finrst = (th->th_flags & (TH_FIN | TH_RST));
 #ifdef DEBUG
 if (estab == 0)
 logprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
@@ -170,8 +174,8 @@
 	      }
 	      gotinfo = 1;
 #ifdef DEBUG
-logprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
-direction, cproto, fp->opt.srcop, fp->opt.dstop, estab);
+logprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d, syn = %d, finrst = %d\n",
+direction, cproto, fp->opt.srcop, fp->opt.dstop, estab, syn, finrst);
 #endif
 	    }
 #ifdef DEBUG
@@ -186,7 +190,11 @@
 		  (fp->opt.dstop == OP_NONE ||
 		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
 	       &&
-		  (fp->opt.estab == 0 || estab)) {
+		  (fp->opt.estab == 0 || estab)
+	       &&
+		  (fp->opt.syn == 0 || syn)
+	       &&
+		  (fp->opt.finrst == 0 || finrst)) {
 		return(fp->action);
 	      }
 	    }
@@ -320,8 +328,9 @@
 {
   u_char *cp;
   struct mbuf *wp;
-  int nb, nw;
+  int nb, nw, diff;
   u_char tunbuff[MAX_MRU];
+  struct in_addr realaddr;
 
   cp = tunbuff;
   nb = 0;
@@ -334,6 +343,10 @@
   if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) {
     pfree(bp);
     return;
+  }
+
+  if(CheckTrans(tunbuff, &realaddr, &diff)) {        /* NAT */
+      ChangeDestIPAddress(tunbuff, realaddr, diff);
   }
 
   ipInOctets += nb;
diff -aurN usr.sbin.original/ppp/ipcp.c usr.sbin/ppp/ipcp.c
--- usr.sbin.original/ppp/ipcp.c	Sun Oct  6 22:32:28 1996
+++ usr.sbin/ppp/ipcp.c	Mon Oct 14 22:23:33 1996
@@ -41,7 +41,7 @@
 extern struct in_addr ifnetmask;
 
 struct ipcpstate IpcpInfo;
-struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress;
+struct in_range DefMyAddress, DefHisAddress, DefTriggerAddress, DefTransAddress;
 
 #ifdef MSEXT
 struct in_addr ns_entries[2], nbns_entries[2];
@@ -153,6 +153,7 @@
 	bcopy(hp->h_addr, (char *)&DefMyAddress.ipaddr.s_addr, hp->h_length);
       }
   }
+  DefTransAddress.ipaddr.s_addr = DefTransAddress.mask.s_addr = 0xffffffff;
 }
 
 void
diff -aurN usr.sbin.original/ppp/ipcp.h usr.sbin/ppp/ipcp.h
--- usr.sbin.original/ppp/ipcp.h	Sun Oct  6 22:32:29 1996
+++ usr.sbin/ppp/ipcp.h	Mon Oct 14 22:23:34 1996
@@ -68,6 +68,7 @@
 extern struct in_range DefMyAddress;
 extern struct in_range DefHisAddress;
 extern struct in_range DefTriggerAddress;
+extern struct in_range DefTransAddress;
 
 #ifdef MSEXT
 extern struct in_addr ns_entries[2];
diff -aurN usr.sbin.original/ppp/lcp.c usr.sbin/ppp/lcp.c
--- usr.sbin.original/ppp/lcp.c	Sun May 12 05:48:28 1996
+++ usr.sbin/ppp/lcp.c	Mon Oct 14 22:24:58 1996
@@ -379,6 +379,7 @@
   StopAllTimers();
   OsLinkdown();
   NewPhase(PHASE_TERMINATE);
+  Prompt(1);
 }
 
 void
@@ -663,6 +664,12 @@
       }
       break;
     }
+#if 1 /* to avoid inf. loop */
+    if (length == 0) {
+      LogPrintf(LOG_LCP, "LCP size zero\n");
+      break;
+    }
+#endif
     plen -= length;
     cp += length;
   }
diff -aurN usr.sbin.original/ppp/main.c usr.sbin/ppp/main.c
--- usr.sbin.original/ppp/main.c	Mon Oct  7 13:21:00 1996
+++ usr.sbin/ppp/main.c	Mon Oct 14 22:24:58 1996
@@ -23,7 +23,17 @@
  *		o Add commands for traffic summary, version display, etc.
  *		o Add signal handler for misc controls.
  */
+
+/*
+ *  rfc1631 : NAT(The IP Network Address Translator) is supported.
+ *  Modified by Junichi SATOH (junichi@astec.co.jp)
+ *
+ *    Sep. 1996 : first version.
+ *    Oct. 1996 : ftp(PORT mode) is fully supported.
+ */
+
 #include "fsm.h"
+#include <string.h>
 #include <fcntl.h>
 #include <paths.h>
 #include <sys/time.h>
@@ -35,6 +45,10 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
 #include "modem.h"
 #include "os.h"
 #include "hdlc.h"
@@ -46,6 +60,7 @@
 #include "filter.h"
 #include "systems.h"
 #include "ip.h"
+#include "nat.h"
 
 #define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
 #define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
@@ -61,8 +76,10 @@
 extern int  SelectSystem();
 
 extern void DecodeCommand(), Prompt();
+extern int aft_cmd;
 extern int IsInteractive();
 extern struct in_addr ifnetmask;
+static UPORT *GetPortPointer();
 static void DoLoop(void);
 static void TerminalStop();
 
@@ -72,6 +89,8 @@
 static int server;
 struct sockaddr_in ifsin;
 char pid_filename[128];
+UPORT *utport[65536], *uuport[65536];
+
 
 static void
 TtyInit()
@@ -455,6 +474,7 @@
   if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
     TtyCommandMode(1);
     fprintf(stderr, "Packet mode.\r\n");
+    aft_cmd = 1;
   }
 }
 
@@ -483,6 +503,7 @@
 #endif
   if (!TermMode) {
     n = read(netfd, linebuff, sizeof(linebuff)-1);
+    aft_cmd = 1;
     if (n > 0) {
       DecodeCommand(linebuff, n, 1);
     } else {
@@ -623,27 +644,475 @@
   }
 }
 
+inline
+void
+RecalcProtoCksum(buf)
+     u_char *buf;
+{
+  static u_short *bp;
+  static union {
+    struct tcphdr *th;
+    struct udphdr *uh;
+  } ph;
+  static u_char savec, *savecp;
+  static u_int hlen, plen, changes;
+  
+  /* recalculate checksum in protocol specific header if needed */
+  switch(((struct ip *)buf)->ip_p){
+  case IPPROTO_UDP:
+    bp = (u_short *)buf;
+    bp += 2 * ((struct ip *)buf)->ip_hl;
+    ph.uh = (struct udphdr *)bp;
+    /* bp/ph.uh points to udp header */
+    ph.uh->uh_sum = 0;
+    hlen = ntohs(((struct ip *)buf)->ip_len);
+    savecp = buf + hlen;
+    savec = *savecp;
+    *savecp = (u_char)0;
+    plen = (hlen -= 4 * ((struct ip *)buf)->ip_hl);
+    changes = 0;
+    hlen++;
+    hlen /= 2;
+    for(; hlen > 0; hlen--)
+      changes += *bp++;
+    *savecp = savec;
+    /* calculate pseudo UDP header */
+    /* source address */
+    bp = (u_short *)&(((struct ip *)buf)->ip_src);
+    changes += *bp++;
+    changes += *bp++;
+    /* destination address */
+    bp = (u_short *)&(((struct ip *)buf)->ip_dst);
+    changes += *bp++;
+    changes += *bp;
+    /* protocol */
+    changes += htons(IPPROTO_UDP); /* protocol */
+    /* UDP length */
+    changes += htons(plen);
+    
+    changes = (changes & 0xffff) + (changes >> 16);
+    changes = (changes & 0xffff) + (changes >> 16);
+    ph.uh->uh_sum = (~changes & 0xffff);
+    LogPrintf(LOG_TCPIP, "UDP check sum is recalculated\n");
+    break;
+  case IPPROTO_TCP:
+    bp = (u_short *)buf;
+    bp += 2 * ((struct ip *)buf)->ip_hl;
+    ph.th = (struct tcphdr *)bp;
+    /* bp/ph.th points to tcp header */
+    ph.th->th_sum = 0;
+    hlen = ntohs(((struct ip *)buf)->ip_len);
+    savecp = buf + hlen;
+    savec = *savecp;
+    *savecp = (u_char)0;
+    plen = (hlen -= 4 * ((struct ip *)buf)->ip_hl);
+    changes = 0;
+    hlen++;
+    hlen /= 2;
+    for(; hlen > 0; hlen--)
+      changes += *bp++;
+    *savecp = savec;
+    /* calculate pseudo TCP header */
+    /* source address */
+    bp = (u_short *)&(((struct ip *)buf)->ip_src);
+    changes += *bp++;
+    changes += *bp++;
+    /* destination address */
+    bp = (u_short *)&(((struct ip *)buf)->ip_dst);
+    changes += *bp++;
+    changes += *bp;
+    /* protocol */
+    changes += htons(IPPROTO_TCP); /* protocol */
+    /* TCP length */
+    changes += htons(plen);
+    
+    changes = (changes & 0xffff) + (changes >> 16);
+    changes = (changes & 0xffff) + (changes >> 16);
+    ph.th->th_sum = (~changes & 0xffff);
+    LogPrintf(LOG_TCPIP, "TCP check sum is recalculated\n");
+    break;
+  default: /* IPPROTO_ICMP */
+  }
+}
+
+void
+ChangeSrcIPAddress(buf, addr)
+     u_char *buf;
+     struct in_addr addr;
+{
+  static u_int changes;
+  static u_int hlen;
+  static u_short *bp;
+  static char msgbuff[100]; /* for debugging message */
+
+  /* if buf has correct IP address, assume it has correct IP checksum */
+  if(((struct ip *)buf)->ip_src.s_addr != addr.s_addr){
+    if(loglevel & (1 << LOG_TCPIP)) /* for spped up when logging is disabled */
+      sprintf(msgbuff, "%s", inet_ntoa(((struct ip *)buf)->ip_src));
+    ((struct ip *)buf)->ip_src = addr;
+    ((struct ip *)buf)->ip_sum = 0;
+
+    /* recalculating checksum in IP header */
+    bp = (u_short *)buf;
+    changes = 0;
+    /* IP header length is (hlen * 2) bytes */
+    for(hlen = 2 * ((struct ip *)buf)->ip_hl; hlen > 0; hlen--)
+      changes += *bp++;
+    changes = (changes & 0xffff) + (changes >> 16);
+    changes = (changes & 0xffff) + (changes >> 16);
+    ((struct ip *)buf)->ip_sum = (~changes & 0xffff);
+
+    if(loglevel & (1 << LOG_TCPIP)) /* for spped up when logging is disabled */
+      LogPrintf(LOG_TCPIP, "Src address changed: %s ---> %s\n",
+		msgbuff,
+		inet_ntoa(((struct ip *)buf)->ip_src));
+  }
+  /* but protocol specific checksum may or may not correct */
+  RecalcProtoCksum(buf);
+}
+
+/* Change ACK number */
+void
+ChangeACKnumber(buf, diff)
+u_char *buf;
+int diff;
+{
+    static u_short *ipheader;
+    static struct tcphdr *tcpheader;
+    u_long acknumber;
+
+    switch(((struct ip *)buf)->ip_p) {
+    case IPPROTO_TCP:
+	ipheader = (u_short *)buf;
+	tcpheader = 
+	  (struct tcphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+	acknumber = ntohl(tcpheader->th_ack);
+	acknumber -= diff;
+	tcpheader->th_ack = ntohl(acknumber);
+	break;
+    default:
+	break;
+    }
+}
+
+/* Change destination IP address */
+void
+ChangeDestIPAddress(buf, realaddr, diff)
+    u_char *buf;
+    struct in_addr realaddr;
+    int diff;
+{
+    static u_int changes;
+    static u_int hlen;
+    static u_short *bp;
+
+    /* Change destination IP address */
+    ((struct ip *)buf)->ip_dst = realaddr;
+    ((struct ip *)buf)->ip_sum = 0;
+
+    /* Change ACK number */
+    if(diff) {
+	ChangeACKnumber(buf, diff);
+    }
+
+    /* recalculating checksum in IP header */
+    bp = (u_short *)buf;
+    changes = 0;
+    /* IP header length is (hlen * 2) bytes */
+    for(hlen = 2 * ((struct ip *)buf)->ip_hl; hlen > 0; hlen--)
+      changes += *bp++;
+    changes = (changes & 0xffff) + (changes >> 16);
+    changes = (changes & 0xffff) + (changes >> 16);
+    ((struct ip *)buf)->ip_sum = (~changes & 0xffff);
+    
+    /* but protocol specific checksum may or may not correct */
+    RecalcProtoCksum(buf);
+}
+
+/* Change SEQ number */
+void
+ChangeSEQnumber(buf, diff)
+u_char *buf;
+int diff;
+{
+    static u_short *ipheader;
+    static struct tcphdr *tcpheader;
+    u_long acknumber;
+
+    switch(((struct ip *)buf)->ip_p) {
+    case IPPROTO_TCP:
+	ipheader = (u_short *)buf;
+	tcpheader = 
+	  (struct tcphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+	acknumber = ntohl(tcpheader->th_seq);
+	acknumber += diff;
+	tcpheader->th_seq = ntohl(acknumber);
+	break;
+    default:
+	break;
+    }
+}
+
+/* Check source IP address and record original information, IP, port.... */
+int
+SourceAddrCheck(buf, n)
+     u_char *buf;
+     int *n;
+{
+    static u_short *ipheader;
+    static struct udphdr *udpheader;
+    static struct tcphdr *tcpheader;
+    static u_short sport, dport;
+    static int ipaddr[5], port[3];
+    UPORT *recstart, *tmp_uuport = NULL, *tmp_utport = NULL;
+    UPORT *data_utport = NULL;
+    int sc_status = 0, i, len;
+    char *tcpdata;
+    static char ipbuf[20];
+    int orglen, newlen;
+    static u_short iplen;
+
+    if((DefTransAddress.ipaddr.s_addr & DefTransAddress.mask.s_addr) == 
+       (((struct ip*)buf)->ip_src.s_addr & DefTransAddress.mask.s_addr)) {
+	ipheader = (u_short *)buf;
+	switch(((struct ip *)buf)->ip_p){
+	case IPPROTO_UDP:
+	    udpheader = 
+	      (struct udphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+	    sport = ntohs(udpheader->uh_sport);
+	    dport = ntohs(udpheader->uh_dport);
+	    if(uuport[sport] != NULL) {
+		recstart = utport[sport];
+		while(recstart) {
+		    if(recstart->dstaddr.s_addr == 
+		       ((struct ip *)buf)->ip_dst.s_addr) {
+			tmp_uuport = recstart;
+			break;
+		    }
+		    recstart = recstart->next;
+		}
+		if(recstart == NULL) {
+		    tmp_uuport = (UPORT*)malloc(sizeof(UPORT));
+		    tmp_uuport->next = uuport[sport];
+		    uuport[sport] = tmp_uuport;
+		}
+	    } else {
+		uuport[sport] = (UPORT*)malloc(sizeof(UPORT));
+		uuport[sport]->next = NULL;
+		tmp_uuport = uuport[sport];
+	    }
+	    tmp_uuport->srcaddr.s_addr = ((struct ip *)buf)->ip_src.s_addr;
+	    tmp_uuport->dstaddr.s_addr = ((struct ip *)buf)->ip_dst.s_addr;
+	    break;
+	case IPPROTO_TCP:
+	    tcpheader = 
+	      (struct tcphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+	    sport = ntohs(tcpheader->th_sport);
+	    dport = ntohs(tcpheader->th_dport);
+	    if(tcpheader->th_flags == TH_SYN) {
+		tmp_utport = GetPortPointer(buf, sport);
+		if(tmp_utport == NULL) {
+		    return -1;
+		}
+		tmp_utport->srcaddr.s_addr = ((struct ip *)buf)->ip_src.s_addr;
+		tmp_utport->dstaddr.s_addr = ((struct ip *)buf)->ip_dst.s_addr;
+		tmp_utport->diff = 0;
+		tmp_utport->flag = 0;
+	    }
+	    if(tcpheader->th_flags & TH_FIN == TH_FIN) {
+		recstart = utport[sport];
+		while(recstart) {
+		    if(recstart->dstaddr.s_addr == 
+		       ((struct ip *)buf)->ip_dst.s_addr) {
+			recstart->flag |= 1;
+		    }
+		    recstart = recstart->next;
+		}
+	    }
+	    if(dport == FTPctrl) {
+		tmp_utport = utport[sport];
+		while(tmp_utport) {
+		    if(tmp_utport->dstaddr.s_addr == 
+		       ((struct ip *)buf)->ip_dst.s_addr) {
+			break;
+		    }
+		    tmp_utport = tmp_utport->next;
+		}
+		if(tmp_utport) {
+		    if(tmp_utport->diff) {
+			ChangeSEQnumber(buf, tmp_utport->diff);
+		    }
+		}
+		tcpdata = (char*)tcpheader + tcpheader->th_off * 4;
+		if(strncmp(tcpdata, "PORT", 4) == 0) {
+		    sscanf(tcpdata, "PORT %d,%d,%d,%d,%d,%d", 
+			   &ipaddr[0], &ipaddr[1], &ipaddr[2], &ipaddr[3],
+			   &port[0], &port[1]);
+		    data_utport = GetPortPointer(buf, port[0] * 256 + port[1]);
+		    if(data_utport != NULL) {
+			data_utport->srcaddr.s_addr = 
+			  ((struct ip *)buf)->ip_src.s_addr;
+			data_utport->dstaddr.s_addr = 
+			  ((struct ip *)buf)->ip_dst.s_addr;
+			data_utport->flag = 0;
+		    }
+		    
+		    orglen = ntohs(((struct ip *)buf)->ip_len) -
+		      (4 * ((struct ip *)buf)->ip_hl + tcpheader->th_off * 4);
+		    sprintf(ipbuf, "%s", inet_ntoa(getCurMyAddr()));
+		    len = strlen(ipbuf);
+		    for(i = 0; i < len; i++) {
+			if(ipbuf[i] == '.') {
+			    ipbuf[i] = ',';
+			}
+		    }
+		    sprintf(tcpdata, "PORT %s,%d,%d\r\n", 
+			    ipbuf, port[0], port[1]);
+		    newlen = strlen(tcpdata);
+
+		    tmp_utport->diff += (newlen - orglen);
+		    iplen = ntohs(((struct ip *)buf)->ip_len);
+		    iplen += (newlen - orglen);
+		    *n = iplen;
+		    ((struct ip *)buf)->ip_len = ntohs(iplen);
+		}
+	    }
+	    break;
+	default:
+	    break;
+	}
+	sc_status = 1;
+    }
+    return sc_status;
+}
+
+/* get pointer to record PORT and IP ADDERSS for TCP */
+UPORT *
+GetPortPointer(buf, sport)
+    u_char *buf;
+    u_short sport;
+{
+    UPORT *recstart, *tmp_utport = NULL;
+
+    if(utport[sport] != NULL) {
+	recstart = utport[sport];
+	while(recstart) {
+	    if(recstart->dstaddr.s_addr == 
+	       ((struct ip *)buf)->ip_dst.s_addr) {
+		if(recstart->flag == 0) {
+		    return NULL;
+		} else {
+		    tmp_utport = recstart;
+		    break;
+		}
+	    }
+	    recstart = recstart->next;
+	}
+	if(recstart == NULL) {
+	    tmp_utport = (UPORT*)malloc(sizeof(UPORT));
+	    tmp_utport->next = utport[sport];
+	    utport[sport] = tmp_utport;
+	}
+    } else {
+	utport[sport] = (UPORT*)malloc(sizeof(UPORT));
+	utport[sport]->next = NULL;
+	tmp_utport = utport[sport];
+    }
+    return tmp_utport;
+}
+
+/* Check if packet should be translated */
+int
+CheckTrans(buf, realaddr, diff)
+    u_char *buf;
+    struct in_addr *realaddr;
+    int *diff;
+{
+    static u_short *ipheader;
+    static struct udphdr *udpheader;
+    static struct tcphdr *tcpheader;
+    static u_short sport, dport;
+    static int ch_flag;
+    UPORT *recstart;
+
+/*    printf("dst=%08x\n", ((struct ip *)buf)->ip_dst.s_addr);*/
+/*    if(((struct ip *)buf)->ip_dst.s_addr == 0x0103a8c0) {
+      realaddr->s_addr = 0x0102a8c0;*/
+
+    ch_flag = 0;
+    ipheader = (u_short *)buf;
+    switch(((struct ip *)buf)->ip_p){
+    case IPPROTO_UDP:
+	udpheader = 
+	  (struct udphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+	sport = ntohs(udpheader->uh_sport);
+	dport = ntohs(udpheader->uh_dport);
+	recstart = uuport[dport];
+	while(recstart) {
+	    if(recstart->dstaddr.s_addr == 
+	       ((struct ip *)buf)->ip_src.s_addr) {
+		realaddr->s_addr = recstart->srcaddr.s_addr;
+		ch_flag = 1;
+		break;
+	    }
+	    recstart = recstart->next;
+	}
+	break;
+    case IPPROTO_TCP:
+	tcpheader = 
+	  (struct tcphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+	sport = ntohs(tcpheader->th_sport);
+	dport = ntohs(tcpheader->th_dport);
+	recstart = utport[dport];
+	while(recstart) {
+	    if(recstart->dstaddr.s_addr == 
+	       ((struct ip *)buf)->ip_src.s_addr) {
+		realaddr->s_addr = recstart->srcaddr.s_addr;
+		if(tcpheader->th_flags & TH_FIN == TH_FIN) {
+		    recstart->flag |= 2;
+		}
+		ch_flag = 1;
+		*diff = recstart->diff;
+		break;
+	    }
+	    recstart = recstart->next;
+	}
+	break;
+    default:
+	break;
+    }
+
+    return ch_flag;
+}
 
 static void
 DoLoop()
 {
   fd_set rfds, wfds, efds;
   int pri, i, n, wfd;
+  int tsavelen = 0;
   struct sockaddr_in hisaddr;
   struct timeval timeout, *tp;
   int ssize = sizeof(hisaddr);
   u_char *cp;
-  u_char rbuff[MAX_MRU];
+  u_char rbuff[MAX_MRU], tbuff[MAX_MRU];
   int dial_up;
   int tries;
   int qlen;
   pid_t pgroup;
+  time_t ttimer = (time_t)0;	/* expiration timer for tun device */
+  struct in_addr oldmyaddr;
+  int recalc;			/* recalculates checksum */
+  int nat;                      /* network address translator */
+  
 
+  recalc = (mode & MODE_AUTO) && (DefMyAddress.width < 32);
   pgroup = getpgrp();
 
   if (mode & MODE_DIRECT) {
     modem = OpenModem(mode);
     LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
+    fflush(stderr);
     PacketMode();
   } else if (mode & MODE_DEDICATED) {
     if (!modem)
@@ -689,6 +1158,7 @@
 	  if (VarDialTries && tries >= VarDialTries) {
 	      dial_up = FALSE;
 	      tries = 0;
+	      tsavelen = 0;
 	  }
 	}
       }
@@ -722,7 +1192,7 @@
 #endif
 
     /* If there are aren't many packets queued, look for some more. */
-    if (qlen < 20)
+    if (qlen < 20 && !tsavelen)
       FD_SET(tun_in, &rfds);
 
     if (netfd > -1) {
@@ -844,6 +1314,20 @@
       }
     }
 
+    if (tsavelen && isOsLinkup()){
+      /* check & reassign source IP address */
+      if(recalc)
+	ChangeSrcIPAddress(tbuff, getCurMyAddr());
+      
+      pri = PacketCheck(tbuff, tsavelen, FL_OUT);
+      if (pri >= 0){
+	IpEnqueue(pri, tbuff, tsavelen);
+      }
+      tsavelen = 0;
+      ttimer = time(NULL) + (time_t)5; /* src IP address check expires in 5 secs */
+      continue;
+    }
+      
     if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
       n = read(tun_in, rbuff, sizeof(rbuff));
       if (n < 0) {
@@ -855,17 +1339,37 @@
        *  device until IPCP is opened.
        */
       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
-	pri = PacketCheck(rbuff, n, FL_DIAL);
+	pri = PacketCheck(rbuff, n, FL_DIAL); /* 1st time */
 	if (pri >= 0) {
-	  IpEnqueue(pri, rbuff, n);
+	  oldmyaddr = DefMyAddress.ipaddr; /* getCurMyAddr(); */
+	  /* IpEnqueue(pri, rbuff, n); */
+	  bcopy(rbuff, tbuff, tsavelen = n);
           dial_up = TRUE;		/* XXX */
 	}
 	continue;
       }
       pri = PacketCheck(rbuff, n, FL_OUT);
-      if (pri >= 0)
-	IpEnqueue(pri, rbuff, n);
+      if (pri >= 0){
+	nat = SourceAddrCheck(rbuff, &n);
+	if(nat >= 0) {
+	    if(recalc || nat){
+		/* when ttimer is set, recalc is always TRUE */
+		if(ttimer || nat){
+		    if(ttimer > time(NULL) || nat){
+			/* check & reassign source IP address */
+			ChangeSrcIPAddress(rbuff, getCurMyAddr());
+		    }else{
+			ttimer = (time_t)0;
+		    }
+		}else{
+		    RecalcProtoCksum(rbuff);
+		}
+	    }
+	    IpEnqueue(pri, rbuff, n);
+	}
+      }
     }
   }
   logprintf("job done.\n");
 }
+
diff -aurN usr.sbin.original/ppp/nat.h usr.sbin/ppp/nat.h
--- usr.sbin.original/ppp/nat.h	Thu Jan  1 09:00:00 1970
+++ usr.sbin/ppp/nat.h	Mon Oct 14 22:23:34 1996
@@ -0,0 +1,19 @@
+/*
+ *  nat.h    for iij-ppp
+ *    by Junichi SATOH (junichi@astec.co.jp)
+ */
+
+/* using ports */
+struct useport {
+    struct useport *next;
+    struct in_addr srcaddr;
+    struct in_addr dstaddr;
+    int diff;
+    u_char flag;
+};
+
+typedef struct useport UPORT;
+
+/* tcp ports for ftp */
+#define FTPctrl 21
+#define FTPdata 20
diff -aurN usr.sbin.original/ppp/os.c usr.sbin/ppp/os.c
--- usr.sbin.original/ppp/os.c	Tue Jun  4 06:35:21 1996
+++ usr.sbin/ppp/os.c	Mon Oct 14 22:23:35 1996
@@ -39,10 +39,11 @@
 #include "arp.h"
 #include "systems.h"
 #include "route.h"
+#include "nat.h"
 
 static struct ifaliasreq ifra;
 static struct ifreq ifrq;
-static struct in_addr oldmine, oldhis;
+static struct in_addr oldmine, oldhis, oldmask;
 static int linkup;
 
 #ifdef bsdi
@@ -50,6 +51,8 @@
 #endif
 extern void HangupModem();
 
+extern UPORT *utport[65536], *uuport[65536];
+
 char *IfDevName;
 
 static int
@@ -137,6 +140,7 @@
     sin->sin_len = sizeof(*sin);
 
     if (changeaddr) {
+      oldmask.s_addr = mask;
       /*
        * Interface already exists. Just change the address.
        */
@@ -200,12 +204,31 @@
 OsLinkdown()
 {
   char *s;
+  struct in_addr zeroaddr;
+  UPORT *tmp_port;
+  int i;
 
   if (linkup) {
     s = (char *)inet_ntoa(peer_addr);
     LogPrintf(LOG_LINK_BIT|LOG_LCP_BIT, "OsLinkdown: %s\n", s);
     if (!(mode & MODE_AUTO))
       DeleteIfRoutes(0);
+    if((mode & MODE_AUTO) && (DefMyAddress.width < 32)){
+      zeroaddr.s_addr = 0;
+      OsSetIpaddress(zeroaddr, oldhis, oldmask);
+    }
+    for(i = 0; i < 65536; i++) {
+	while(utport[i]) {
+	    tmp_port = utport[i];
+	    utport[i] = utport[i]->next;
+	    free(tmp_port);
+	}
+	while(uuport[i]) {
+	    tmp_port = uuport[i];
+	    uuport[i] = uuport[i]->next;
+	    free(tmp_port);
+	}
+    }
     linkup = 0;
   }
 }
@@ -348,6 +371,17 @@
 {
 }
 
+int
+isOsLinkup()
+{
+  return linkup;
+}
+
+struct in_addr
+getCurMyAddr()
+{
+  return oldmine;
+}
 void
 OsAddOutOctets(cnt)
 int cnt;
diff -aurN usr.sbin.original/ppp/os.h usr.sbin/ppp/os.h
--- usr.sbin.original/ppp/os.h	Thu Jan 11 06:27:57 1996
+++ usr.sbin/ppp/os.h	Mon Oct 14 22:22:19 1996
@@ -34,4 +34,6 @@
 void DeleteIfRoutes __P((int));
 void OsAddInOctets __P((int cnt));
 void OsAddOutOctets __P((int cnt));
+int isOsLinkup __P((void));
+struct in_addr getCurMyAddr __P((void));
 #endif
diff -aurN usr.sbin.original/ppp/passwdauth.c usr.sbin/ppp/passwdauth.c
--- usr.sbin.original/ppp/passwdauth.c	Sun Oct  6 22:32:31 1996
+++ usr.sbin/ppp/passwdauth.c	Mon Oct 14 22:35:00 1996
@@ -22,7 +22,11 @@
 #include <sys/types.h>
 #include <utmp.h>
 #include <time.h>
+#ifdef __FreeBSD__
 #include <libutil.h>
+#else
+#include <util.h>
+#endif
 #include <pwd.h>
 #include "fsm.h"
 #include "passwdauth.h"
diff -aurN usr.sbin.original/ppp/pathnames.h usr.sbin/ppp/pathnames.h
--- usr.sbin.original/ppp/pathnames.h	Tue May 30 12:50:54 1995
+++ usr.sbin/ppp/pathnames.h	Mon Oct 14 22:27:53 1996
@@ -51,7 +51,7 @@
 #endif
 #define	_PATH_PHONES		"/etc/phones"
 #define	_PATH_REMOTE		"/etc/remote"
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__)
 #define _PATH_PPP		"/etc/ppp"
 #else
 #define _PATH_PPP		"/etc"
diff -aurN usr.sbin.original/ppp/route.c usr.sbin/ppp/route.c
--- usr.sbin.original/ppp/route.c	Sun Oct  6 22:32:35 1996
+++ usr.sbin/ppp/route.c	Mon Oct 14 22:24:57 1996
@@ -198,10 +198,12 @@
 #if (BSD >= 199306)
   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
     perror("sysctl-getroute");
+    free(sp);
     return(1);
   }
 #else
   if (getkerninfo(KINFO_RT_DUMP, sp, &needed, 0) < 0)
+    free(sp);
     return(1);
 #endif
   ep = sp + needed;
@@ -226,11 +228,11 @@
 #endif
 	wp = (u_char *)(lp + 1);
 	mask = 0;
-	for (nb = *lp; nb > 4; nb--) {
+	for (nb = *(char *)lp; nb > 4; nb--) {
 	  mask <<= 8;
 	  mask |= *wp++;
 	}
-	for (nb = 8 - *lp; nb > 0; nb--)
+	for (nb = 8 - *(char *)lp; nb > 0; nb--)
 	  mask <<= 8;
       }
     }
@@ -238,7 +240,7 @@
     p_flags(rtm->rtm_flags & (RTF_UP|RTF_GATEWAY|RTF_HOST), "%-6.6s ");
     printf("(%d)\n", rtm->rtm_index);
   }
-
+  free(sp);
   return(1);
 }
 

