diff -r -N -c ppp.ORG/Makefile ppp/Makefile
*** ppp.ORG/Makefile	Thu Oct 22 11:32:48 1998
--- ppp/Makefile	Thu Mar 11 22:39:44 1999
***************
*** 5,11 ****
  	datalink.c deflate.c defs.c filter.c fsm.c hdlc.c id.c iface.c ip.c \
  	ipcp.c iplist.c lcp.c link.c log.c lqr.c main.c mbuf.c modem.c \
  	mp.c pap.c physical.c pred.c probe.c prompt.c route.c server.c \
! 	sig.c slcompress.c systems.c throughput.c timer.c tun.c vjcomp.c
  CFLAGS+=-Wall
  LDADD+= -lutil -lz
  DPADD+=	${LIBUTIL} ${LIBZ}
--- 5,12 ----
  	datalink.c deflate.c defs.c filter.c fsm.c hdlc.c id.c iface.c ip.c \
  	ipcp.c iplist.c lcp.c link.c log.c lqr.c main.c mbuf.c modem.c \
  	mp.c pap.c physical.c pred.c probe.c prompt.c route.c server.c \
! 	sig.c slcompress.c systems.c throughput.c timer.c tun.c vjcomp.c \
! 	nat.c
  CFLAGS+=-Wall
  LDADD+= -lutil -lz
  DPADD+=	${LIBUTIL} ${LIBZ}
diff -r -N -c ppp.ORG/bundle.c ppp/bundle.c
*** ppp.ORG/bundle.c	Wed Jan  6 09:08:03 1999
--- ppp/bundle.c	Thu Mar 11 22:40:38 1999
***************
*** 90,95 ****
--- 90,96 ----
  #include "datalink.h"
  #include "ip.h"
  #include "iface.h"
+ #include "nat.h"
  
  #define SCATTER_SEGMENTS 4	/* version, datalink, name, physical */
  #define SOCKET_OVERHEAD	100	/* additional buffer space for large */
***************
*** 98,103 ****
--- 99,107 ----
  static int bundle_RemainingIdleTime(struct bundle *);
  static int bundle_RemainingAutoLoadTime(struct bundle *);
  
+ int tsavelen = 0;
+ u_char tbuff[MAX_MRU];
+ 
  static const char *PhaseNames[] = {
    "Dead", "Establish", "Authenticate", "Network", "Terminate"
  };
***************
*** 591,596 ****
--- 595,601 ----
                        const fd_set *fdset)
  {
    struct datalink *dl;
+   int nat;
  
    if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
      descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
***************
*** 639,644 ****
--- 644,662 ----
       * Process on-demand dialup. Output packets are queued within tunnel
       * device until IPCP is opened.
       */
+     if (tsavelen && bundle_Phase(bundle) == PHASE_NETWORK){
+         /* check & reassign source IP address */
+ 	nat = SourceAddrCheck(bundle, tun.data, &n);
+         if(nat)
+           ChangeSrcIPAddress(tbuff, bundle->ncp.ipcp.my_ip);
+         
+         pri = PacketCheck(bundle, tbuff, tsavelen, &bundle->filter.out);
+         if (pri >= 0){
+             ip_Enqueue(&bundle->ncp.ipcp, pri, tbuff, tsavelen);
+         }
+         tsavelen = 0;
+ 	return;
+     }
  
      if (bundle_Phase(bundle) == PHASE_DEAD) {
        /*
***************
*** 658,665 ****
--- 676,692 ----
          return;
      }
  
+     if (bundle_Phase(bundle) < PHASE_NETWORK) {
+       bcopy(tun.data, tbuff, tsavelen = n);
+       return;
+     }
+ 
      pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out);
      if (pri >= 0) {
+       nat = SourceAddrCheck(bundle, tun.data, &n);
+       if(nat) {
+ 	ChangeSrcIPAddress(tun.data, bundle->ncp.ipcp.my_ip);
+       }
  #ifndef NOALIAS
        if (bundle->AliasEnabled) {
          PacketAliasOut(tun.data, sizeof tun.data);
***************
*** 857,862 ****
--- 884,891 ----
    /* Send over the first physical link by default */
    ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
              &bundle.fsm);
+ 
+   nat_Init(&bundle);
  
    memset(&bundle.filter, '\0', sizeof bundle.filter);
    bundle.filter.in.fragok = bundle.filter.in.logok = 1;
diff -r -N -c ppp.ORG/bundle.h ppp/bundle.h
*** ppp.ORG/bundle.h	Fri Dec 11 03:36:30 1998
--- ppp/bundle.h	Thu Mar 11 22:39:44 1999
***************
*** 137,142 ****
--- 137,147 ----
    struct {
      struct pppTimer timer;      /* choked output queue timer */
    } choked;
+ 
+   struct {
+     struct in_range trance_range;
+     struct in_range xtrance_range;
+   } nat;
  };
  
  #define descriptor2bundle(d) \
diff -r -N -c ppp.ORG/command.c ppp/command.c
*** ppp.ORG/command.c	Mon Dec 14 10:15:34 1998
--- ppp/command.c	Thu Mar 11 22:39:44 1999
***************
*** 1711,1716 ****
--- 1711,1775 ----
    return -1;
  }
  
+ /* Set IP address should be translated. (NAT) */
+ static int
+ SetTranslationAddr(struct cmdargs const *arg)
+ {
+   struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
+   struct in_range *trance_range = &arg->bundle->nat.trance_range;
+ 
+   trance_range->ipaddr.s_addr = 0xffffffff;
+ 
+   if (arg->argc > 3)
+     return -1;
+ 
+   if (arg->argc > 0) {
+     if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
+                    &trance_range->ipaddr, &trance_range->mask,
+                    &trance_range->width))
+       return 1;
+   }
+   /*
+    *  0.0.0.0 and 255.255.255.255 means no translation
+    */
+   if (trance_range->ipaddr.s_addr == 0xffffffff || 
+       trance_range->ipaddr.s_addr == 0) {
+     trance_range->mask.s_addr = 0xffffffff;
+     trance_range->width = 32;
+   }
+   return 0;
+ }
+ 
+ /* Set X server IP address translation. (NAT) */
+ static int
+ SetXTranslationAddr(struct cmdargs const *arg)
+ {
+   struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
+   struct in_range *xtrance_range = &arg->bundle->nat.xtrance_range;
+ 
+   xtrance_range->ipaddr.s_addr = 0xffffffff;
+ 
+   if (arg->argc > 3)
+     return -1;
+ 
+   if (arg->argc > 0) {
+     if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
+                    &xtrance_range->ipaddr, &xtrance_range->mask,
+                    &xtrance_range->width))
+       return 1;
+   }
+ 
+   /*
+    *  0.0.0.0 and 255.255.255.255 means no translation
+    */
+   if (xtrance_range->ipaddr.s_addr == 0xffffffff || 
+       xtrance_range->ipaddr.s_addr == 0) {
+     xtrance_range->mask.s_addr = 0xffffffff;
+     xtrance_range->width = 32;
+   }
+   return 0;
+ }
+ 
  static struct cmdtab const SetCommands[] = {
    {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
    "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
***************
*** 1757,1762 ****
--- 1816,1825 ----
    "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
    {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
    "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
+   {"taddr",  NULL, SetTranslationAddr,   LOCAL_AUTH, "translation-addr",
+   "set taddr [trans-addr [netmask [trg-addr]]]"},
+   {"xaddr",  NULL, SetXTranslationAddr,  LOCAL_AUTH, "xtranslation-addr",
+   "set xaddr [xtrans-addr]"},
    {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
    "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
    {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
diff -r -N -c ppp.ORG/ip.c ppp/ip.c
*** ppp.ORG/ip.c	Tue Nov 10 09:32:39 1998
--- ppp/ip.c	Thu Mar 11 22:39:44 1999
***************
*** 70,75 ****
--- 70,76 ----
  #include "vjcomp.h"
  #include "tun.h"
  #include "ip.h"
+ #include "nat.h"
  
  static const u_short interactive_ports[32] = {
    544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
***************
*** 393,398 ****
--- 394,403 ----
    struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
  #endif
  
+   int diff;
+   struct in_addr realaddr;
+   int ck_sum_status;
+ 
    tun_fill_header(tun, AF_INET);
    cp = tun.data;
    nb = 0;
***************
*** 406,411 ****
--- 411,422 ----
      memcpy(cp, MBUF_CTOP(wp), wp->cnt);
      cp += wp->cnt;
      nb += wp->cnt;
+   }
+ 
+   ck_sum_status = CheckCheckSum(tun.data);
+ 
+   if(CheckTrans(bundle, tun.data, &realaddr, &diff)) {        /* NAT */
+       ChangeDestIPAddress(tun.data, realaddr, diff, ck_sum_status);
    }
  
  #ifndef NOALIAS
diff -r -N -c ppp.ORG/ipcp.c ppp/ipcp.c
*** ppp.ORG/ipcp.c	Wed Feb  3 05:27:47 1999
--- ppp/ipcp.c	Thu Mar 11 22:39:44 1999
***************
*** 711,716 ****
--- 711,721 ----
    }
  
    ipcp_Setup(ipcp);
+ 
+   ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
+   if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
+     log_Printf(LogERROR, "ipcpLayerDown: unable to set ip address\n");
+   }
  }
  
  int
diff -r -N -c ppp.ORG/lcp.c ppp/lcp.c
*** ppp.ORG/lcp.c	Wed Jan 13 06:50:20 1999
--- ppp/lcp.c	Thu Mar 11 22:39:44 1999
***************
*** 65,70 ****
--- 65,71 ----
  #include "cbcp.h"
  #include "datalink.h"
  #include "bundle.h"
+ #include "nat.h"
  
  /* for received LQRs */
  struct lqrreq {
***************
*** 456,461 ****
--- 457,464 ----
    hdlc_StopTimer(&p->hdlc);
    lqr_StopTimer(p);
    lcp_Setup(fsm2lcp(fp), 0);
+ 
+   ClearTable();
  }
  
  static int
diff -r -N -c ppp.ORG/main.c ppp/main.c
*** ppp.ORG/main.c	Tue Feb  2 18:41:03 1999
--- ppp/main.c	Thu Mar 11 22:41:35 1999
***************
*** 22,27 ****
--- 22,81 ----
   *	TODO:
   */
  
+ /*
+  *  rfc1631 : NAT(The IP Network Address Translator) is supported.
+  *  Modified by Junichi SATOH (junichi@astec.co.jp)  in 1996-1998.
+  *
+  *  * NOTICE *
+  *     IIJ-PPP in FreeBSD distributions is already include "Packet Aliasing".
+  *     Purpose of both this NAT patch and the "Packet Aliasing" is IP 
+  *     masquerade, but features are different. 
+  *
+  *     This NAT patch support more protocols than "Packet Aliasing".
+  *     For example, X, rlogin, RealAudio, VDOLiveVideo, CU-SeeMe, etc...
+  *     
+  *     After appling this NAT patch, IIJ-PPP includes both IP masquerade
+  *     codes.
+  *
+  *     ** If you use '-alias' option, don't use 'set taddr' command. **
+  *     ** If you use 'set taddr' command, don't use '-alias' option. **
+  *
+  *
+  *  Original distribution sites of NAT patch:
+  *    Japanese : http://www2a.biglobe.ne.jp/~junichi/index.html
+  *    English  : http://www2a.biglobe.ne.jp/~junichi/index-e.html
+  *
+  *  1996
+  *    Sep.    : first version.
+  *    Oct. 10 : Fully support of ftp(PORT mode).
+  *         18 : Fix of following bugs.
+  *              - miss calculation of SEQ and ACK number when retry
+  *                sending a packet.
+  *              - ppp process is dead by force disconnection
+  *                during ftp execution.
+  *         26 : Fix of Memory leak.
+  *              Fully support of Realaudio.
+  *         28 : Support Time limit of translation table.
+  *    Nov.  2 : Support of ICMP.
+  *    Dec. 23 : Support of Auto mapping port numbers.
+  *              Support of X server's address setting.
+  *  1997
+  *    Jan. 15 : Support of filtering incomming packets after re-addressing.
+  *              Fix of not recalculate checksum on error packets.
+  *    Feb. 15 : Support of VDO Live Video.
+  *    Mar. 29 : Changed base iij-ppp source, included in 2.2.1-RELEASE.
+  *              Merge On-demand patch made by NOROP.
+  *              Support of Diablo (Thanks to Miyashita)
+  *    May. 18 : Fix VDOLive.
+  *    Jun.  7 : Fix port number changing problem.
+  *    Oct.  1 : Support CU-SeeMe (Thanks to Kawai)
+  *    Nov.  5 : Changed base iij-ppp source, included in 2.2.5-RELEASE.
+  *    Dec. 28 : Fix UDP packet check sum problem.
+  *  1998
+  *    Mar. 28 : Changed base iij-ppp source, included in 2.2.6-RELEASE.
+  *    Dec.  6 : Changed base iij-ppp source, included in 2.2.8-RELEASE.
+  */
+ 
  #include <sys/types.h>
  #include <netinet/in.h>
  #include <netinet/in_systm.h>
***************
*** 76,81 ****
--- 130,136 ----
  #include "cbcp.h"
  #include "datalink.h"
  #include "iface.h"
+ #include "nat.h"
  
  #ifndef O_NONBLOCK
  #ifdef O_NDELAY
***************
*** 108,113 ****
--- 163,173 ----
    exit(excode);
  }
  
+ UPORT *utport[65536], *uuport[65536];
+ SPUPORT *uraport, *uvdoport, *udiaport;
+ ICMPADDR *icmpaddr;
+ u_short sub_port, real_port;
+ 
  static void
  CloseConnection(int signo)
  {
***************
*** 254,259 ****
--- 314,320 ----
    int nfds, mode, alias, label, arg;
    struct bundle *bundle;
    struct prompt *prompt;
+   int i;
  
    nfds = getdtablesize();
    if (nfds >= FD_SETSIZE)
***************
*** 271,276 ****
--- 332,344 ----
  #ifndef NOALIAS
    PacketAliasInit();
  #endif
+   for(i = 0; i < 65536; i++) {
+     utport[i] = uuport[i] = NULL;
+   }
+   uraport = NULL;
+   uvdoport = NULL;
+   udiaport = NULL;
+   icmpaddr = NULL;
    label = ProcessArgs(argc, argv, &mode, &alias);
  
  #ifdef __FreeBSD__
diff -r -N -c ppp.ORG/nat.c ppp/nat.c
*** ppp.ORG/nat.c	Thu Jan  1 09:00:00 1970
--- ppp/nat.c	Thu Mar 11 22:39:44 1999
***************
*** 0 ****
--- 1,1249 ----
+ /*
+  *  NAT module for iij-ppp
+  *    Programmed by Junichi SATOH (junichi@astec.co.jp) in 1996,1997,1998.
+  */
+ 
+ #include <sys/param.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/in.h>
+ #include <netinet/ip.h>
+ #include <netinet/tcp.h>
+ #include <netinet/udp.h>
+ #include <netinet/ip_icmp.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+ #include <net/route.h>
+ #include <netdb.h>
+ #include <net/if.h>
+ #include <sys/sockio.h>
+ #include <sys/un.h>
+ #include <arpa/nameser.h>
+ 
+ #include <fcntl.h>
+ #include <resolv.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/errno.h>
+ #include <termios.h>
+ #include <unistd.h>
+ 
+ #include "probe.h"
+ #include "mbuf.h"
+ #include "log.h"
+ #include "defs.h"
+ #include "id.h"
+ #include "timer.h"
+ #include "fsm.h"
+ #include "lqr.h"
+ #include "hdlc.h"
+ #include "lcp.h"
+ #include "ccp.h"
+ #include "iplist.h"
+ #include "throughput.h"
+ #include "slcompress.h"
+ #include "ipcp.h"
+ #include "filter.h"
+ #include "descriptor.h"
+ #include "link.h"
+ #include "mp.h"
+ #include "bundle.h"
+ #include "auth.h"
+ #include "systems.h"
+ #include "sig.h"
+ #include "main.h"
+ #include "server.h"
+ #include "prompt.h"
+ #include "chat.h"
+ #include "chap.h"
+ #include "cbcp.h"
+ #include "datalink.h"
+ #include "nat.h"
+ 
+ static UPORT *GetUPortPointer();
+ static UPORT *GetPortPointer();
+ static void cu_check_out();
+ static void cu_check_in();
+ 
+ extern UPORT *utport[65536], *uuport[65536];
+ extern SPUPORT *uraport, *uvdoport, *udiaport;
+ extern ICMPADDR *icmpaddr;
+ extern u_short sub_port, real_port;
+ 
+ /* get pointer to table of PORT and IP ADDERSS for UDP */
+ UPORT *
+ GetUPortPointer(buf, sport, real_port, subport, sc_status)
+ u_char *buf;
+ u_short sport;
+ u_short real_port;
+ u_short *subport;
+ int sc_status;
+ {
+     UPORT *recstart, *tmp_uuport = NULL, *prev_uuport, *ret_port;
+ 
+     *subport = sport;
+     if(uuport[sport] != NULL) {
+ 	recstart = uuport[sport];
+ 	prev_uuport = NULL;
+ 	while(recstart) {
+ 	    if(recstart->dstaddr.s_addr == 
+ 	       ((struct ip *)buf)->ip_dst.s_addr) {
+ 		if(recstart->lm_time + KEEP_UDP < time(NULL) ||
+ 		   recstart->srcaddr.s_addr == ((struct ip *)buf)->ip_src.s_addr) {
+ 		    tmp_uuport = recstart;
+ 		    tmp_uuport->real_port = real_port;
+ 		    tmp_uuport->subport = *subport;
+ 		    break;
+ 		} else {
+ 		    sport--;
+ 		    if(sport < 1000) {
+ 			sport = 30000;
+ 		    }
+ 		    ret_port = GetUPortPointer(buf, sport, real_port, 
+ 					       subport, sc_status);
+ 		    tmp_uuport = (UPORT*)malloc(sizeof(UPORT));
+ 		    tmp_uuport->next = uuport[sport];
+ 		    uuport[sport] = tmp_uuport;
+ 		    tmp_uuport->subport = *subport;
+ 		    tmp_uuport->real_port = real_port;
+ 		    tmp_uuport->dstaddr.s_addr = 
+ 		      ((struct ip *)buf)->ip_dst.s_addr;
+ 		    if(sc_status == 1) {
+ 			tmp_uuport->srcaddr.s_addr =
+ 			  ((struct ip *)buf)->ip_src.s_addr;
+ 		    } else {
+ 			tmp_uuport->srcaddr.s_addr = 0xffffffff;
+ 		    }
+ 		    return ret_port;
+ 		}
+ 	    }
+ 	    if(recstart->lm_time + KEEP_UDP < time(NULL) && prev_uuport) {
+ 		prev_uuport->next = recstart->next;
+ 		free(recstart);
+ 		recstart = prev_uuport->next;
+ 	    } else {
+ 		prev_uuport = recstart;
+ 		recstart = recstart->next;
+ 	    }
+ 	}
+ 	if(recstart == NULL) {
+ 	    tmp_uuport = (UPORT*)malloc(sizeof(UPORT));
+ 	    tmp_uuport->next = uuport[sport];
+ 	    tmp_uuport->real_port = real_port;
+ 	    tmp_uuport->subport = *subport;
+ 	    uuport[sport] = tmp_uuport;
+ 	}
+     } else {
+ 	uuport[sport] = (UPORT*)malloc(sizeof(UPORT));
+ 	uuport[sport]->next = NULL;
+ 	uuport[sport]->real_port = real_port;
+ 	uuport[sport]->subport = *subport;
+ 	tmp_uuport = uuport[sport];
+     }
+     return tmp_uuport;
+ }
+ 
+ /* get pointer to table of PORT and IP ADDERSS for TCP */
+ UPORT *
+ GetPortPointer(bundle, buf, sport, real_port, subport, sc_status)
+     struct bundle *bundle;
+     u_char *buf;
+     u_short sport;
+     u_short real_port;
+     u_short *subport;
+     int sc_status;
+ {
+     UPORT *recstart, *tmp_utport = NULL, *ret_port;
+     struct in_addr myaddr;
+ 
+     *subport = sport;
+     if(utport[sport] != NULL) {
+ 	recstart = utport[sport];
+ 	while(recstart) {
+ 	    if(recstart->dstaddr.s_addr == 
+ 	       ((struct ip *)buf)->ip_dst.s_addr) {
+ 		myaddr = bundle->ncp.ipcp.my_ip;
+ 		if(recstart->flag == 0 && 
+ 		   recstart->srcaddr.s_addr != ((struct ip *)buf)->ip_src.s_addr &&
+ 		   !(recstart->srcaddr.s_addr == 0xffffffff && ((struct ip *)buf)->ip_src.s_addr == myaddr.s_addr)) {
+ 		    sport--;
+ 		    if(sport < 1000) {
+ 			sport = 30000;
+ 		    }
+ 		    ret_port = GetPortPointer(bundle, buf, sport, real_port, 
+ 					      subport, sc_status);
+ 		    tmp_utport = (UPORT*)malloc(sizeof(UPORT));
+ 		    tmp_utport->next = utport[sport];
+ 		    utport[sport] = tmp_utport;
+ 		    tmp_utport->subport = *subport;
+ 		    tmp_utport->real_port = real_port;
+ 		    tmp_utport->dstaddr.s_addr = 
+ 		      ((struct ip *)buf)->ip_dst.s_addr;
+ 		    if(sc_status == 1) {
+ 			tmp_utport->srcaddr.s_addr =
+ 			  ((struct ip *)buf)->ip_src.s_addr;
+ 		    } else {
+ 			tmp_utport->srcaddr.s_addr = 0xffffffff;
+ 		    }
+ 		    return ret_port;
+ 		} else {
+ 		    tmp_utport = recstart;
+ 		    break;
+ 		}
+ 	    }
+ 	    recstart = recstart->next;
+ 	}
+ 	if(recstart == NULL) {
+ 	    tmp_utport = (UPORT*)malloc(sizeof(UPORT));
+ 	    tmp_utport->next = utport[sport];
+ 	    tmp_utport->real_port = real_port;
+ 	    tmp_utport->subport = *subport;
+ 	    utport[sport] = tmp_utport;
+ 	}
+     } else {
+ 	utport[sport] = (UPORT*)malloc(sizeof(UPORT));
+ 	utport[sport]->next = NULL;
+ 	utport[sport]->real_port = real_port;
+ 	utport[sport]->subport = *subport;
+ 	tmp_utport = utport[sport];
+     }
+     return tmp_utport;
+ }
+ 
+ /* get pointer to table of IP ADDERSS for ICMP */
+ ICMPADDR*
+ GetICMPAddrPointer(buf)
+     u_char *buf;
+ {
+     ICMPADDR *tmp_icmpaddr = NULL, *icmp_recstart, *prev_icmpaddr;
+ 
+     if(icmpaddr != NULL) {
+ 	icmp_recstart = icmpaddr;
+ 	prev_icmpaddr = NULL;
+ 	while(icmp_recstart) {
+ 	    if(icmp_recstart->dstaddr.s_addr == 
+ 	       ((struct ip *)buf)->ip_dst.s_addr) {
+ 		tmp_icmpaddr = icmp_recstart;
+ 		break;
+ 	    }
+ 	    if(icmp_recstart->lm_time + KEEP_ICMP < time(NULL) && 
+ 	       prev_icmpaddr) {
+ 		prev_icmpaddr->next = icmp_recstart->next;
+ 		free(icmp_recstart);
+ 		icmp_recstart = prev_icmpaddr->next;
+ 	    } else {
+ 		prev_icmpaddr = icmp_recstart;
+ 		icmp_recstart = icmp_recstart->next;
+ 	    }
+ 	}
+ 	if(icmp_recstart == NULL) {
+ 	    tmp_icmpaddr = (ICMPADDR*)malloc(sizeof(ICMPADDR));
+ 	    tmp_icmpaddr->next = icmpaddr;
+ 	    icmpaddr = tmp_icmpaddr;
+ 	}
+     } else {
+ 	icmpaddr = (ICMPADDR*)malloc(sizeof(UPORT));
+ 	icmpaddr->next = NULL;
+ 	tmp_icmpaddr = icmpaddr;
+     }
+     return tmp_icmpaddr;
+ }
+ 
+ /* Change SEQ number */
+ void
+ ChangeSEQnumber(buf, diff)
+ u_char *buf;
+ int diff;
+ {
+     static u_short *ipheader;
+     static struct tcphdr *tcpheader;
+     u_long seqnumber;
+ 
+     switch(((struct ip *)buf)->ip_p) {
+     case IPPROTO_TCP:
+ 	ipheader = (u_short *)buf;
+ 	tcpheader = 
+ 	  (struct tcphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+ 	seqnumber = ntohl(tcpheader->th_seq);
+ 	seqnumber += diff;
+ 	tcpheader->th_seq = ntohl(seqnumber);
+ 	break;
+     default:
+ 	break;
+     }
+ }
+ 
+ void
+ write_subport_difftmp(tmp_utport)
+ UPORT *tmp_utport;
+ {
+     UPORT *recstart;
+ 
+     recstart = utport[tmp_utport->subport];
+     while(recstart) {
+ 	if(recstart->dstaddr.s_addr == tmp_utport->dstaddr.s_addr &&
+ 	   recstart->srcaddr.s_addr == tmp_utport->srcaddr.s_addr) {
+ 	    recstart->diff_tmp = tmp_utport->diff_tmp;
+ 	}
+ 	recstart = recstart->next;
+     }
+ }
+ 
+ /* Check source IP address and record original information, IP, port.... */
+ int
+ SourceAddrCheck(bundle, buf, n)
+      struct bundle *bundle;
+      u_char *buf;
+      int *n;
+ {
+     struct in_range *trance_range = &bundle->nat.trance_range;
+ 
+     static u_short *ipheader;
+     static struct udphdr *udpheader;
+     static struct tcphdr *tcpheader;
+     static struct icmp *icmpheader;
+     static u_short sport, dport, subport, ftpport, ftpsubport;
+     static int ipaddr[5], port[3];
+     UPORT *recstart, *tmp_uuport = NULL, *tmp_utport = NULL;
+     UPORT *data_utport = NULL, *prev_utport;
+     ICMPADDR *tmp_icmpaddr;
+     SPUPORT *tmp_uraport, *tmp_uvdoport, *tmp_udiaport;
+     int sc_status = 0, i, j, k, len, c_count;
+     char *tcpdata, tmp_tcpdata[2000];
+     static char ipbuf[20], portdata[50];
+     int orglen, newlen, portdata_len;
+     static u_short iplen;
+ 
+     if((trance_range->ipaddr.s_addr & trance_range->mask.s_addr) == 
+        (((struct ip*)buf)->ip_src.s_addr & trance_range->mask.s_addr) ||
+        ((struct ip*)buf)->ip_src.s_addr == 0) {
+ 	sc_status = 1;
+     }
+     ipheader = (u_short *)buf;
+     switch(((struct ip *)buf)->ip_p) {
+     case IPPROTO_UDP:
+ 	sub_port = 0;
+ 	udpheader = 
+ 	  (struct udphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+ 	sport = ntohs(udpheader->uh_sport);
+ 	dport = ntohs(udpheader->uh_dport);
+ 	tmp_uuport = GetUPortPointer(buf, sport, sport, &subport, sc_status);
+ 	if(sc_status == 1) {
+ 	    tmp_uuport->srcaddr.s_addr = ((struct ip *)buf)->ip_src.s_addr;
+ 	} else {
+ 	    tmp_uuport->srcaddr.s_addr = 0xffffffff;
+ 	}
+ 	tmp_uuport->dstaddr.s_addr = ((struct ip *)buf)->ip_dst.s_addr;
+ 	tmp_uuport->lm_time = time(NULL);
+ 	if(dport == CUSeeMe) {
+ 	    cu_check_out(bundle, buf);
+ 	}
+ 	break;
+     case IPPROTO_TCP:
+ 	sub_port = 0;
+ 	tcpheader = 
+ 	  (struct tcphdr *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+ 	sport = ntohs(tcpheader->th_sport);
+ 	dport = ntohs(tcpheader->th_dport);
+ 	if(sport >= XPORT_BEGIN && sport <= XPORT_END) {
+ 	    break;
+ 	}
+ 	if(tcpheader->th_flags == TH_SYN) {
+ 	    tmp_utport = GetPortPointer(bundle, buf, sport, sport,
+ 					&subport, sc_status);
+ 	    sub_port = subport;
+ 	    if(tmp_utport == NULL) {
+ 		return -1;
+ 	    }
+ 	    if(sc_status == 1) {
+ 		tmp_utport->srcaddr.s_addr = ((struct ip *)buf)->ip_src.s_addr;
+ 	    } else {
+ 		tmp_utport->srcaddr.s_addr = 0xffffffff;
+ 	    }
+ 	    tmp_utport->dstaddr.s_addr = ((struct ip *)buf)->ip_dst.s_addr;
+ 	    tmp_utport->diff = 0;
+ 	    tmp_utport->diff_tmp = 0;
+ 	    tmp_utport->flag = 0;
+ 	    tmp_utport->lm_time = time(NULL);
+ 	    if(dport == RealAudio && sc_status == 1) {
+ 		tmp_uraport = (SPUPORT*)malloc(sizeof(SPUPORT));
+ 		tmp_uraport->udplink = tmp_utport;
+ 		tmp_uraport->next = uraport;
+ 		uraport = tmp_uraport;
+ 	    }
+ 	    if((dport == VDO1 || dport == VDO2) && sc_status == 1) {
+ 		tmp_uvdoport = (SPUPORT*)malloc(sizeof(SPUPORT));
+ 		tmp_uvdoport->udplink = tmp_utport;
+ 		tmp_uvdoport->next = uvdoport;
+ 		uvdoport = tmp_uvdoport;
+ 	    }
+ 	    if((dport == DIATCP0 || dport == DIATCP1) && sc_status == 1) {
+                 tmp_udiaport = (SPUPORT*)malloc(sizeof(SPUPORT));
+                 tmp_udiaport->udplink = tmp_utport;
+                 tmp_udiaport->next = udiaport;
+                 udiaport = tmp_udiaport;
+             }
+ 	}
+ 	if((tcpheader->th_flags & TH_FIN) == TH_FIN) {
+ 	    recstart = utport[sport];
+ 	    prev_utport = NULL;
+ 	    while(recstart) {
+ 		if(recstart->dstaddr.s_addr == 
+ 		   ((struct ip *)buf)->ip_dst.s_addr) {
+ 		    recstart->flag |= 1;
+ 		    recstart->lm_time = time(NULL);
+ 		    sub_port = recstart->subport;
+ 		}
+ 		if(recstart->lm_time + KEEP_TCP < time(NULL) && prev_utport) {
+ 		    prev_utport->next = recstart->next;
+ 		    free(recstart);
+ 		    recstart = prev_utport->next;
+ 		} else {
+ 		    prev_utport = recstart;
+ 		    recstart = recstart->next;
+ 		}
+ 	    }
+ 	}
+ 	if(dport == FTPctrl && sc_status == 1) {
+ 	    tmp_utport = utport[sport];
+ 	    while(tmp_utport) {
+ 		if(tmp_utport->dstaddr.s_addr == 
+ 		   ((struct ip *)buf)->ip_dst.s_addr) {
+ 		    sub_port = tmp_utport->subport;
+ 		    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;
+ 	    orglen = ntohs(((struct ip *)buf)->ip_len) -
+ 	      (4 * ((struct ip *)buf)->ip_hl + tcpheader->th_off * 4);
+ 	    for (i = 0; i < orglen - 4; i++) {
+ 		if (tcpdata[i    ] == 'P' &&
+ 		    tcpdata[i + 1] == 'O' &&
+ 		    tcpdata[i + 2] == 'R' &&
+ 		    tcpdata[i + 3] == 'T') {
+ 		    sscanf(tcpdata + i, "PORT %d,%d,%d,%d,%d,%d", 
+ 			   &ipaddr[0], &ipaddr[1], &ipaddr[2], &ipaddr[3],
+ 			   &port[0], &port[1]);
+ 		    ftpport = port[0] * 256 + port[1];
+ 		    data_utport = GetPortPointer(bundle, buf, ftpport,
+ 						 ftpport, 
+ 						 &ftpsubport, sc_status);
+ 		    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;
+ 			data_utport->diff = 0;
+ 			data_utport->diff_tmp = 0;
+ 			data_utport->lm_time = time(NULL);
+ 		    }
+ 
+ 		    c_count = 0;
+ 		    for (j = i; j < orglen; j++) {
+ 			if (c_count == 5) {
+ 			    if (tcpdata[j] < '0' || tcpdata[j] > '9') {
+ 				break;
+ 			    }
+ 			}
+ 			if (c_count < 5 && tcpdata[j] == ',') {
+ 			    c_count++;
+ 			}
+ 		    }
+ 		    bcopy(tcpdata + j, tmp_tcpdata, orglen - j);
+ 		    
+ 		    sprintf(ipbuf, "%s", inet_ntoa(bundle->ncp.ipcp.my_ip));
+ 		    len = strlen(ipbuf);
+ 		    for(k = 0; k < len; k++) {
+ 			if(ipbuf[k] == '.') {
+ 			    ipbuf[k] = ',';
+ 			}
+ 		    }
+ 		    port[0] = ftpsubport >> 8;
+ 		    port[1] = ftpsubport & 0xff;
+ 		    sprintf(portdata, "PORT %s,%d,%d", ipbuf, port[0], port[1]);
+ 		    portdata_len = strlen(portdata);
+ 		    
+ 		    bcopy (portdata, tcpdata + i, portdata_len);
+ 		    bcopy (tmp_tcpdata, tcpdata + i + portdata_len, orglen - j);
+ 		    newlen = i + portdata_len + orglen - j;
+ 		    if(tmp_utport) {
+ 			tmp_utport->diff_tmp = (newlen - orglen);
+ 			if(sport != subport) {
+ 			    write_subport_difftmp(tmp_utport);
+ 			}
+ 		    }
+ 		    iplen = ntohs(((struct ip *)buf)->ip_len);
+ 		    iplen += (newlen - orglen);
+ 		    *n = iplen;
+ 		    ((struct ip *)buf)->ip_len = ntohs(iplen);
+ 		    break;
+ 		}
+ 	    }
+ 	}
+ 	if(sub_port == 0) {
+ 	    tmp_utport = utport[sport];
+ 	    while(tmp_utport) {
+ 		if(tmp_utport->dstaddr.s_addr == 
+ 		   ((struct ip *)buf)->ip_dst.s_addr) {
+ 		    if(tmp_utport->srcaddr.s_addr ==
+ 		       ((struct ip *)buf)->ip_src.s_addr ||
+ 		       tmp_utport->srcaddr.s_addr == 0xffffffff) {
+ 			sub_port = tmp_utport->subport;
+ 		    }
+ 		    break;
+ 		}
+ 		tmp_utport = tmp_utport->next;
+ 	    }
+ 	}
+ 	if(sub_port != sport && sub_port) {
+ 	    sc_status = 1;
+ 	}
+ 	break;
+     case IPPROTO_ICMP:
+ 	sub_port = 0;
+ 	icmpheader = 
+ 	  (struct icmp *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+ 	if(icmpheader->icmp_type == ICMP_ECHO) {
+ 	    tmp_icmpaddr = GetICMPAddrPointer(buf);
+ 	    if(sc_status == 1) {
+ 		tmp_icmpaddr->srcaddr.s_addr = 
+ 		  ((struct ip *)buf)->ip_src.s_addr;
+ 	    } else {
+ 		tmp_icmpaddr->srcaddr.s_addr = 0xffffffff;
+ 	    }
+ 	    tmp_icmpaddr->dstaddr.s_addr = ((struct ip *)buf)->ip_dst.s_addr;
+ 	    tmp_icmpaddr->lm_time = time(NULL);
+ 	}
+ 	break;
+     default:
+ 	break;
+     }
+ 
+     return sc_status;
+ }
+ 
+ void
+ write_realport_diff(subport)
+ UPORT *subport;
+ {
+     UPORT *recstart;
+ 
+     recstart = utport[subport->real_port];
+     while(recstart) {
+ 	if(recstart->dstaddr.s_addr == subport->dstaddr.s_addr &&
+ 	   recstart->srcaddr.s_addr == subport->srcaddr.s_addr) {
+ 	    recstart->diff_tmp = subport->diff_tmp;
+ 	    recstart->diff = subport->diff;
+ 	}
+ 	recstart = recstart->next;
+     }
+ }
+ 
+ SPUPORT* CheckSpecialUDP(SPUPORT *spport, u_char *buf, int dport, 
+ 			 struct in_addr *realaddr)
+ {
+     SPUPORT *prev_spport, *tmp_spport;
+     UPORT *tmp_uuport;
+ 
+     prev_spport = NULL;
+     tmp_spport = spport;
+     while(tmp_spport) {
+ 	if(tmp_spport->udplink->dstaddr.s_addr == 
+ 	   ((struct ip *)buf)->ip_src.s_addr) {
+ 	    if(prev_spport == NULL) {
+ 		spport = tmp_spport->next;
+ 	    } else {
+ 		prev_spport->next = tmp_spport->next;
+ 	    }
+ 	    realaddr->s_addr = tmp_spport->udplink->srcaddr.s_addr;
+ 	    tmp_uuport = (UPORT*)malloc(sizeof(UPORT));
+ 	    tmp_uuport->srcaddr.s_addr = 
+ 	      tmp_spport->udplink->srcaddr.s_addr;
+ 	    tmp_uuport->dstaddr.s_addr = 
+ 	      tmp_spport->udplink->dstaddr.s_addr;
+ 	    tmp_uuport->next = uuport[dport];
+ 	    tmp_uuport->real_port = dport;
+ 	    tmp_uuport->subport = dport;
+ 	    uuport[dport] = tmp_uuport;
+ 	    free(tmp_spport);
+ 	    break;
+ 	}
+ 	prev_spport = tmp_spport;
+ 	tmp_spport = tmp_spport->next;
+     }
+     return spport;
+ }
+ 
+ /* Check if packet should be translated */
+ int
+ CheckTrans(bundle, buf, realaddr, diff)
+     struct bundle *bundle;
+     u_char *buf;
+     struct in_addr *realaddr;
+     int *diff;
+ {
+     struct in_range *xtrance_range = &bundle->nat.xtrance_range;
+     static u_short *ipheader;
+     static struct udphdr *udpheader;
+     static struct tcphdr *tcpheader;
+     static struct icmp *icmpheader;
+     static u_short sport, dport;
+     static int ch_flag;
+     UPORT *recstart;
+     ICMPADDR *icmp_recstart;
+     static struct ip *er_ipheader;
+ 
+     ch_flag = 0;
+     ipheader = (u_short *)buf;
+     switch(((struct ip *)buf)->ip_p){
+     case IPPROTO_UDP:
+ 	udpheader = 
+ 	  (struct udphdr *)((char*)ipheader + 
+ 			    (((struct ip *)buf)->ip_hl << 2));
+ 	sport = ntohs(udpheader->uh_sport);
+ 	dport = ntohs(udpheader->uh_dport);
+ 	/* Check RealAudio UDP packet. */
+ 	if(dport >= RAUDP_L && dport <= RAUDP_H) {
+ 	    uraport = CheckSpecialUDP(uraport, buf, dport, realaddr);
+ 	}
+ 	/* Check Diablo UDP packet. */
+ 	if(dport == DIAUDP0) {
+ 	    udiaport = CheckSpecialUDP(udiaport, buf, dport, realaddr);
+         }
+ 	/* Check VDOLiveVideo UDP packet. */
+ 	uvdoport = CheckSpecialUDP(uvdoport, buf, dport, realaddr);
+ 	recstart = uuport[dport];
+ 	while(recstart) {
+ 	    if(recstart->dstaddr.s_addr == 
+ 	       ((struct ip *)buf)->ip_src.s_addr) {
+ 		if(recstart->srcaddr.s_addr != 0xffffffff) {
+ 		    realaddr->s_addr = recstart->srcaddr.s_addr;
+ 		    if(dport == CUSeeMe) {
+ 			cu_check_in(buf, recstart);
+ 		    }
+ 		    ch_flag = 1;
+ 		}
+ 		real_port = recstart->real_port;
+ 		break;
+ 	    }
+ 	    recstart = recstart->next;
+ 	}
+ 	break;
+     case IPPROTO_TCP:
+ 	tcpheader = 
+ 	  (struct tcphdr *)((char*)ipheader + 
+ 			    (((struct ip *)buf)->ip_hl << 2));
+ 	sport = ntohs(tcpheader->th_sport);
+ 	dport = ntohs(tcpheader->th_dport);
+ 	if(dport >= XPORT_BEGIN && dport <= XPORT_END) {
+ 	    if(xtrance_range->ipaddr.s_addr != 0 &&
+ 	       xtrance_range->ipaddr.s_addr != 0xffffffff) {
+ 		realaddr->s_addr = xtrance_range->ipaddr.s_addr;
+ 		real_port = dport;
+ 		ch_flag = 1;
+ 		break;
+ 	    }
+ 	}
+ 	recstart = utport[dport];
+ 	while(recstart) {
+ 	    if(recstart->dstaddr.s_addr == 
+ 	       ((struct ip *)buf)->ip_src.s_addr) {
+ 		if(recstart->srcaddr.s_addr != 0xffffffff) {
+ 		    realaddr->s_addr = recstart->srcaddr.s_addr;
+ 		    if((tcpheader->th_flags & TH_FIN) == TH_FIN) {
+ 			recstart->flag |= 2;
+ 		    }
+ 		    ch_flag = 1;
+ 		    recstart->diff += recstart->diff_tmp;
+ 		    recstart->diff_tmp = 0;
+ 		    if(dport != recstart->real_port) {
+ 			write_realport_diff(recstart);
+ 		    }
+ 		    *diff = recstart->diff;
+ 		}
+ 		real_port = recstart->real_port;
+ 		break;
+ 	    }
+ 	    recstart = recstart->next;
+ 	}
+ 	break;
+     case IPPROTO_ICMP:
+ 	icmpheader = 
+ 	  (struct icmp *)(ipheader + 2 * ((struct ip *)buf)->ip_hl);
+ 	if(icmpheader->icmp_type == ICMP_ECHOREPLY) {
+ 	    icmp_recstart = icmpaddr;
+ 	    while(icmp_recstart) {
+ 		if(icmp_recstart->dstaddr.s_addr == 
+ 		   ((struct ip *)buf)->ip_src.s_addr) {
+ 		    if(icmp_recstart->srcaddr.s_addr != 0xffffffff) {
+ 			realaddr->s_addr = icmp_recstart->srcaddr.s_addr;
+ 			ch_flag = 1;
+ 		    }
+ 		    break;
+ 		}
+ 		icmp_recstart = icmp_recstart->next;
+ 	    }
+ 	}
+ 	if(icmpheader->icmp_type == ICMP_UNREACH || 
+ 	   icmpheader->icmp_type == ICMP_TIMXCEED) {
+ 	    er_ipheader = &icmpheader->icmp_ip;
+ 	    switch(er_ipheader->ip_p) {
+ 	    case IPPROTO_UDP:
+ 		udpheader = 
+ 		  (struct udphdr *)((char*)er_ipheader + 
+ 				    (er_ipheader->ip_hl << 2));
+ 		sport = ntohs(udpheader->uh_sport);
+ 		dport = ntohs(udpheader->uh_dport);
+ 		recstart = uuport[sport];
+ 		while(recstart) {
+ 		    if(recstart->dstaddr.s_addr == 
+ 		       er_ipheader->ip_dst.s_addr) {
+ 			if(recstart->srcaddr.s_addr != 0xffffffff) {
+ 			    realaddr->s_addr = recstart->srcaddr.s_addr;
+ 			    ch_flag = 1;
+ 			}
+ 			real_port = recstart->real_port;
+ 			break;
+ 		    }
+ 		    recstart = recstart->next;
+ 		}
+ 		break;
+ 	    case IPPROTO_TCP:
+ 		tcpheader = 
+ 		  (struct tcphdr *)(er_ipheader + 2 * er_ipheader->ip_hl);
+ 		sport = ntohs(tcpheader->th_sport);
+ 		dport = ntohs(tcpheader->th_dport);
+ 		recstart = utport[sport];
+ 		while(recstart) {
+ 		    if(recstart->dstaddr.s_addr == 
+ 		       er_ipheader->ip_dst.s_addr) {
+ 			if(recstart->srcaddr.s_addr != 0xffffffff) {
+ 			    realaddr->s_addr = recstart->srcaddr.s_addr;
+ 			    ch_flag = 1;
+ 			}
+ 			real_port = recstart->real_port;
+ 			break;
+ 		    }
+ 		    recstart = recstart->next;
+ 		}
+ 		break;
+ 	    }
+ 	}
+ 	break;
+     default:
+ 	break;
+     }
+ 
+     return ch_flag;
+ }
+ 
+ int
+ CheckCheckSum(buf)
+ u_char *buf;
+ {
+     static u_int changes;
+     static u_int hlen;
+     static u_short *bp;
+     u_short sum_back;
+ 
+     static union {
+ 	struct tcphdr *th;
+ 	struct udphdr *uh;
+ 	struct icmp *icmp;
+     } ph;
+     static u_char savec, *savecp;
+     static u_int plen;
+ 
+     /* Save CheckSum */
+     sum_back = ((struct ip *)buf)->ip_sum;
+     ((struct ip *)buf)->ip_sum = 0;
+ 
+     /* calculating 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);
+ 
+     /* Check CheckSum */
+     ((struct ip *)buf)->ip_sum = sum_back;
+     if(((struct ip *)buf)->ip_sum != (~changes & 0xffff)) {
+ 	return -1;
+     }
+ 
+     /* check checksum in protocol specific header */
+     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 */
+ 	if (ph.uh->uh_sum == 0) {
+ 	    /* checksum unused */
+ 	    break;
+ 	}
+ 	sum_back = ph.uh->uh_sum;
+ 	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 = sum_back;
+ 	if(ph.uh->uh_sum != (~changes & 0xffff)) {
+ 	    return -1;
+ 	}
+ 	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 */
+ 	sum_back = ph.th->th_sum;
+ 	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 = sum_back;
+ 	if(ph.th->th_sum != (~changes & 0xffff)) {
+ 	    return -1;
+ 	}
+ 	break;
+     case IPPROTO_ICMP:
+ 	break;
+     default:
+ 	break;
+     }
+ 
+     return 0;
+ }
+ 
+ 
+ /* Check CU-SeeMe packet and translate address */
+ /* This part is based on CUSeeMe masquerading module for Linux */
+ 
+ /*
+  *              IP_MASQ_FTP CUSeeMe masquerading module
+  *
+  *
+  * Version:     @(#)ip_masq_cuseeme.c 0.02   07/23/96
+  *
+  * Author:      Richard Lynch
+  *
+  *
+  * Fixes:
+  *      Richard Lynch           :       Updated patch to conform to new module
+  *                                      specifications
+  *      Nigel Metheringham      :       Multiple port support
+  *      Michael Owings          :       Fixed broken init code
+  *                                      Added code to update inbound
+  *                                      packets with correct local addresses. Fixes audio
+  *                                      and "chat" problems
+  *                                      Thanx to the CU-SeeMe Consortium for
+  *                                      technical docs
+  *
+  *
+  *
+  *      This program is free software; you can redistribute it and/or
+  *      modify it under the terms of the GNU General Public License
+  *      as published by the Free Software Foundation; either version
+  *      2 of the License, or (at your option) any later version.
+  *
+  */
+ void
+ cu_check_out(bundle, buf)
+ struct bundle *bundle;
+ char *buf;
+ {
+     struct ip *iph = (struct ip*)buf;
+     struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ip_hl * 4]);
+     cu_header *cu_head;
+     char *data = (char *)&uh[1];
+     struct in_addr addr;
+ 
+     if(uh->uh_ulen >= sizeof(cu_header)) {
+ 	cu_head         = (cu_header *) data;
+ 	/* cu_head->port   = ms->mport; */
+ 	if( cu_head->addr ) {
+ 	    addr = bundle->ncp.ipcp.my_ip;
+ 	    cu_head->addr = (u_long)addr.s_addr;
+ 	}
+     }
+     return;
+ }
+ 
+ void
+ cu_check_in(buf, recstart)
+ char *buf;
+ UPORT *recstart;
+ {
+     struct ip *iph = (struct ip*)buf;
+     struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ip_hl * 4]);
+     cu_header *cu_head;
+     oc_header       *oc;
+     client_info     *ci;
+     char *data = (char *)&uh[1];
+     u_short len = uh->uh_ulen;
+     int             i, off;
+ 
+     if (len >= sizeof(cu_header)) {
+ 	cu_head         = (cu_header *) data;
+ 	if(cu_head->dest_addr) /* Correct destination address */
+ 	  cu_head->dest_addr = (u_long)recstart->srcaddr.s_addr;
+ 	if(ntohs(cu_head->data_type) == 101 && len > sizeof(oc_header)) {
+ 	    oc = (oc_header * ) data;
+ 	    /* Spin (grovel) thru client_info structs till we find our own */
+ 	    off = sizeof(oc_header);
+ 	    for(i = 0; i < oc->client_count && off + sizeof(client_info)
+ 		<= len; i++) {       
+ 		ci = (client_info *)(data + off);
+ 		if(ci->address == (u_long)iph->ip_dst.s_addr) {
+ 		    /* Update w/ our real ip address and exit */
+ 		    ci->address = (u_long)recstart->srcaddr.s_addr;
+ 		    break;
+ 		} else
+ 		  off += sizeof(client_info);
+ 	    }
+ 	}
+     }
+ }
+ 
+ inline
+ void
+ RecalcProtoCksum(buf, direction)
+ u_char *buf;
+ int direction;
+ {
+     static u_short *bp;
+     static union {
+ 	struct tcphdr *th;
+ 	struct udphdr *uh;
+ 	struct icmp *icmp;
+     } 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;
+ 	if(direction == POUT) {
+ 	    if(sub_port == 0) {
+ 		sub_port = ntohs(ph.uh->uh_sport);
+ 	    }
+ 	    ph.uh->uh_sport = 0;
+ 	} else {
+ 	    if(real_port == 0) {
+ 		real_port = ntohs(ph.uh->uh_dport);
+ 	    }
+ 	    ph.uh->uh_dport = 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);
+  
+ 	if(direction == POUT) {
+ 	    sub_port = ntohs(sub_port);
+ 	    changes += sub_port;
+ 	    ph.uh->uh_sport = sub_port;
+ 	} else {
+ 	    real_port = ntohs(real_port);
+ 	    changes += real_port;
+ 	    ph.uh->uh_dport = real_port;
+ 	}    
+ 	changes = (changes & 0xffff) + (changes >> 16);
+ 	changes = (changes & 0xffff) + (changes >> 16);
+ 	ph.uh->uh_sum = (~changes & 0xffff);
+ 	log_Printf(LogTCPIP, "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;
+  
+ 	if(direction == POUT) {
+ 	    if(sub_port == 0) {
+ 		sub_port = ntohs(ph.th->th_sport);
+ 	    }
+ 	    ph.th->th_sport = 0;
+ 	} else {
+ 	    if(real_port == 0) {
+ 		real_port = ntohs(ph.th->th_dport);
+ 	    }
+ 	    ph.th->th_dport = 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);
+  
+ 	if(direction == POUT) {
+ 	    sub_port = ntohs(sub_port);
+ 	    changes += sub_port;
+ 	    ph.th->th_sport = sub_port;
+ 	} else {
+ 	    real_port = ntohs(real_port);
+ 	    changes += real_port;
+ 	    ph.th->th_dport = real_port;
+ 	}
+ 	changes = (changes & 0xffff) + (changes >> 16);
+ 	changes = (changes & 0xffff) + (changes >> 16);
+ 	ph.th->th_sum = (~changes & 0xffff);
+  
+ 	log_Printf(LogTCPIP, "TCP check sum is recalculated\n");
+ 	break;
+     case IPPROTO_ICMP:
+ 	break;
+     default:
+ 	break;
+     }
+ }
+  
+ 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(log_IsKept(LogTCPIP)) /* 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(log_IsKept(LogTCPIP)) /* for spped up when logging is disabled */
+ 	 log_Printf(LogTCPIP, "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, POUT);
+ }
+ 
+ /* 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, ck_sum_status)
+ u_char *buf;
+ struct in_addr realaddr;
+ int diff;
+ int ck_sum_status;
+ {
+     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);
+     if(ck_sum_status == 0) {
+ 	((struct ip *)buf)->ip_sum = (~changes & 0xffff);
+     }
+      
+     /* but protocol specific checksum may or may not correct */
+     if(ck_sum_status == 0) {
+ 	RecalcProtoCksum(buf, PIN);
+     }
+ }
+ 
+ void nat_Init(struct bundle *bundle)
+ {
+   struct in_range *trance_range = &bundle->nat.trance_range;
+   struct in_range *xtrance_range = &bundle->nat.xtrance_range;
+ 
+   trance_range->ipaddr.s_addr = trance_range->mask.s_addr = 0xffffffff;
+   xtrance_range->ipaddr.s_addr = xtrance_range->mask.s_addr = 0xffffffff;
+ }
+ 
+ void
+ FreeSpecialUDP(SPUPORT *spport)
+ {
+     SPUPORT *tmp_spport;
+ 
+     while(spport) {
+       tmp_spport = spport;
+       spport = spport->next;
+       free(tmp_spport);
+     }
+ }
+ 
+ void
+ ClearTable()
+ {
+   UPORT *tmp_port;
+   ICMPADDR *tmp_icmpaddr;
+   int i;
+ 
+   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);
+       }
+     }
+     FreeSpecialUDP(uraport);
+     FreeSpecialUDP(uvdoport);
+     FreeSpecialUDP(udiaport);
+     uraport = uvdoport = udiaport = NULL;
+     while(icmpaddr) {
+       tmp_icmpaddr = icmpaddr;
+       icmpaddr = icmpaddr->next;
+       free(tmp_icmpaddr);
+     }
+ }
diff -r -N -c ppp.ORG/nat.h ppp/nat.h
*** ppp.ORG/nat.h	Thu Jan  1 09:00:00 1970
--- ppp/nat.h	Thu Mar 11 22:39:45 1999
***************
*** 0 ****
--- 1,112 ----
+ /*
+  *  nat.h    for iij-ppp
+  *    by Junichi SATOH (junichi@astec.co.jp)  1996,1997,1998.
+  */
+ 
+ extern int SourceAddrCheck();
+ extern void ChangeSrcIPAddress();
+ extern void RecalcProtoCksum();
+ extern int CheckTrans();
+ extern int CheckCheckSum();
+ extern void ChangeDestIPAddress();
+ extern void nat_Init(struct bundle *);
+ extern void ClearTable();
+ 
+ /* using ports */
+ struct useport {
+     struct useport *next;
+     struct in_addr srcaddr;
+     struct in_addr dstaddr;
+     u_short real_port;
+     u_short subport;
+     short diff;
+     short diff_tmp;
+     time_t lm_time;
+     u_char flag;
+ };
+ 
+ /* Special UDP port */
+ struct special_udp {
+     struct useport *udplink;
+     struct special_udp *next;
+ };
+ 
+ /* address translation table for ICMP(echo) packets */
+ struct icmpaddr {
+     struct icmpaddr *next;
+     struct in_addr srcaddr;
+     struct in_addr dstaddr;
+     time_t lm_time;
+ };
+ 
+ /* CU-SeeMe Data Header */
+ typedef struct {
+     u_short dest_family;
+     u_short dest_port;
+     u_long  dest_addr;
+     short family;
+     u_short port;
+     u_long addr;
+     u_long seq;
+     u_short msg;
+     u_short data_type;
+     u_short packet_len;
+ } cu_header;
+ 
+ /* Open Continue Header */
+ typedef struct  {
+     cu_header       cu_head;
+     u_short client_count; /* Number of client info structs */
+     u_long  seq_no;
+     char            user_name[20];
+     char            stuff[4]; /* flags,  version stuff,  etc */
+ } oc_header;
+ 
+ /* client info structures */
+ typedef struct {
+     u_long address; /* Client address */
+     char stuff[8]; /* Flags, pruning bitfield,  packet counts etc */
+ } client_info;
+ 
+ 
+ typedef struct special_udp SPUPORT;
+ typedef struct useport UPORT;
+ typedef struct icmpaddr ICMPADDR;
+ 
+ /* Time to keep a exchanging table. (sec) */
+ #define KEEP_TCP 10 * 60
+ #define KEEP_UDP 10
+ #define KEEP_ICMP 2
+ 
+ /* tcp ports for ftp */
+ #define FTPctrl 21
+ #define FTPdata 20
+ 
+ /* RealAudio */
+ /* server tcp port */
+ #define RealAudio 7070
+ /* client udp port */
+ #define RAUDP_L 1000
+ #define RAUDP_H 9999
+ 
+ /* VDOLive Video */
+ #define VDO1 7000
+ #define VDO2 7010
+ 
+ /* Diablo Battle.net */
+ /* server tcp port */
+ #define DIATCP0        116
+ #define DIATCP1 118
+ /* client udp port */
+ #define DIAUDP0 6112
+ 
+ /* CU-SeeME */
+ #define CUSeeMe 7648
+ 
+ /* PORT numbers */
+ #define POUT 0
+ #define PIN 1
+ 
+ /* port number used by X-window system */
+ #define XPORT_BEGIN 6000
+ #define XPORT_END 6063
