diff -uNr freeswan-2.02.stock/Makefile freeswan-2.02/Makefile
--- freeswan-2.02.stock/Makefile	2003-06-18 02:25:05.000000000 -0400
+++ freeswan-2.02/Makefile	2003-10-10 22:27:20.000000000 -0400
@@ -139,6 +139,10 @@
 		'CONFIG_IPSEC' $(PATCHES)/net/Makefile.fs2_2.patch
 	@$(PATCHER) -v $(KERNELSRC) net/ipv4/af_inet.c \
 		'CONFIG_IPSEC' $(PATCHES)/net/ipv4/af_inet.c.fs2_2.patch
+	@$(PATCHER) -v $(KERNELSRC) net/ipv4/udp.c \
+		'CONFIG_IPSEC' $(PATCHES)/net/ipv4/udp.c.fs2_2.patch
+	@$(PATCHER) -v $(KERNELSRC) include/net/sock.h \
+		'CONFIG_IPSEC' $(PATCHES)/net/include.net.sock.h.fs2_2.patch
 # Removed patches, will unpatch automatically.
 	@$(PATCHER) -v $(KERNELSRC) include/linux/proc_fs.h
 	@$(PATCHER) -v $(KERNELSRC) net/core/dev.c
@@ -161,6 +165,10 @@
 		'CONFIG_IPSEC' $(PATCHES)/net/Makefile.fs2_4.patch
 	@$(PATCHER) -v $(KERNELSRC) net/ipv4/af_inet.c \
 		'CONFIG_IPSEC' $(PATCHES)/net/ipv4/af_inet.c.fs2_4.patch
+	@$(PATCHER) -v $(KERNELSRC) net/ipv4/udp.c \
+		'CONFIG_IPSEC' $(PATCHES)/net/ipv4/udp.c.fs2_4.patch
+	@$(PATCHER) -v $(KERNELSRC) include/net/sock.h \
+		'CONFIG_IPSEC' $(PATCHES)/net/include.net.sock.h.fs2_4.patch
 # Removed patches, will unpatch automatically.
 	@$(PATCHER) -v $(KERNELSRC) include/linux/proc_fs.h
 	@$(PATCHER) -v $(KERNELSRC) net/core/dev.c
diff -uNr freeswan-2.02.stock/README.NAT-Traversal freeswan-2.02/README.NAT-Traversal
--- freeswan-2.02.stock/README.NAT-Traversal	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/README.NAT-Traversal	2003-10-10 22:27:20.000000000 -0400
@@ -0,0 +1,206 @@
+
+NAT-Traversal Patch -- Version 0.6   [ Contributed by Arkoon Network Security ]
+===================================  [                  http://www.arkoon.net ]
+                                     [          http://open-source.arkoon.net ]
+
+NAT-Traversal patch allows FreeS/WAN to be used behind any NAT device
+by encapsuling ESP in UDP.
+
+Send all your comments/requests to me (mlafon@arkoon.net). If you use it and
+find it useful, drop me a mail too.
+
+
+Supported drafts :
+------------------
+
+  o draft-ietf-ipsec-nat-t-ike-01.txt
+  o draft-ietf-ipsec-udp-encaps-01.txt
+  o draft-ietf-ipsec-nat-t-ike-02.txt
+  o draft-ietf-ipsec-udp-encaps-02.txt
+  o draft-ietf-ipsec-nat-t-ike-03.txt
+  o draft-ietf-ipsec-udp-encaps-03.txt
+  o draft-ietf-ipsec-nat-t-ike-04.txt
+  o draft-ietf-ipsec-udp-encaps-04.txt
+
+
+Notes :
+-------
+
+  o Transport mode has been disabled due to security concerns (see below for
+    details).  Enable it AT YOUR OWN RISK.
+
+  o Using Tunnel mode with roadwarriors, you will need to specify the internal
+    IP in the FreeS/WAN Configuration or use Virtual IP (see below).
+      ex:
+        right=%any
+        rightsubnet=192.168.1.1/32
+
+  o x509/RSA is strongly recomended for authentication or you'll have to use
+    the same PSK for every users.
+
+  o This patch also includes VendorID identification. If you know/encounter
+    other VendorID values/hash, please send them to me.
+
+  o draft-ietf-ipsec-nat-t-ike-01 (used by SSH-Sentinel and SafeNet) does
+    not work if the NAT-Device is doing Ipsec PassThrough.
+
+
+Virtual IP :
+------------
+
+  This patch also include a method to allow roadwarriors to 'choose' their
+  IP in a list of allowed networks.
+
+  For each connection, you can allow roadwarrior to choose their IP
+  following different methods :
+    ...
+    right=%any
+    rightsubnet=vhost:%no,%priv
+    ...
+
+  virtual subnet is a network type (vhost or vnet) followed by a list of
+  method :
+    %no    = no virtual IP (accept public IP)
+    %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP  [not implemented]
+    %ike  = accept affected IKE Config Mode IP         [not implemented]
+    %priv = accept system-wide private net list
+    %v4:x = accept ipv4 in list 'x'
+    %v6:x = accept ipv6 in list 'x'
+    %all  = accept all ips                             [only for testing]
+
+  The system-wide private net list is define in the 'config setup' section
+  and contain a list of allowed networks and a list of not allowed networks.
+
+  The recommended value is all RFC1918 private networks minus your own
+  private networks.
+
+  By example (RFC1918 - 192.168.2.0/24 - 192.168.15.128/25) :
+    virtual_private=%v4:10.0.0.0/8,%v4:172.16.0.0/12,%v4:192.168.0.0/16,%v4:!192.168.2.0/24,%v4:!192.168.15.128/25
+
+  Note: you can also use subnetwithin from the x509 patch to handle virtual IP.
+
+
+Install :
+---------
+
+  o apply NAT-T patch in freeswan directory :
+
+    - FreeS/WAN 1.99:
+        NAT-Traversal-0.6-freeswan-1.99.diff
+
+    - FreeS/WAN 1.99 + NotifyDelete + x509 0.9.15 + Alg 0.8.0 :
+        NAT-Traversal-0.6-freeswan-1.99-nd-x509-0.9.15-alg.diff
+
+    - FreeS/WAN 1.99 + NotifyDelete + x509 0.9.31 + Alg 0.8.0 :
+        NAT-Traversal-0.6-freeswan-1.99-nd-x509-0.9.31-alg.diff
+
+    - FreeS/WAN 2.00 + x509 1.3.5 :
+        NAT-Traversal-0.6-freeswan-2.00-x509-1.3.5.diff
+
+    - Super FreeS/WAN 2.00-rc3 :
+        NAT-Traversal-0.6-sfs-2.00rc3.diff
+
+    $ cd ~/dev/freeswan-1.99/
+    $ cat ~/NAT-Traversal-0.6-freeswan-1.99.diff | patch -p1
+
+  o Follow the FreeS/WAN procedure to rebuild all. When doing kernel
+    configuration, don't forget to select CONFIG_IPSEC_NAT_TRAVERSAL.
+
+  o install new kernel, pluto, whack, _confread, _plutorun, _realsetup
+  o add 'nat_traversal=yes' to your ipsec.conf (config setup)
+  o reboot with the new kernel
+
+
+Tests (only Tunnel Mode) :
+--------------------------
+
+  o SSH Sentinel 1.3         [ nat-t-ike-01 ]  : OK
+  o SSH Sentinel 1.3.1       [ nat-t-ike-01 ]  : OK
+  o SSH Sentinel 1.4         [ nat-t-ike-01 ]  : OK
+  o SafeNet SoftRemote 8.0   [ nat-t-ike-01 ]  : OK
+  o FreeS/WAN + NAT-T        [ nat-t-ike-01 ]  : OK
+  o FreeS/WAN + NAT-T        [ nat-t-ike-03 ]  : OK
+
+Note:
+  SSH Sentinel has a bug during diagnostic. It sends ENCAPSULATION_MODE_TUNNEL
+  instead of ENCAPSULATION_MODE_UDP_TUNNEL. This is not refused to allow good
+  interoperability with SSH but will be removed as soon as Sentinel is fixed.
+  If you don't want this behavior, you can add this line in spdb.c :
+  > #define I_DONT_CARE_OF_SSH_SENTINEL
+
+
+Security Concerns :
+-------------------
+
+  o Transport Mode can't be used without NAT in the IPSec layer. Otherwise,
+    all packets for the NAT device (including all hosts behind it) would be
+    sent to the NAT-T Client. This would create a sort of blackhole between
+    the peer which is not behind NAT and the NAT device.
+
+  o In Tunnel Mode with roadwarriors, we CAN'T accept any IP address,
+    otherwise, an evil roadwarrior could redirect all trafic for one host
+    (including a host on the private network) to himself. That's why, you have
+    to specify the private IP in the configuration file, use virtual IP
+    management, or DHCP-over-IPSec.
+
+
+Todo :
+------
+
+  o accept new NAT mapping with different IP address
+  o smaller patch for net/ipv4/udp.c (?)
+  o do not send keep alive if packets have been sent to peer (?)
+
+
+Changes :
+---------
+
+  o Version 0.1 -- First public release
+
+  o Version 0.2
+    - verify that rcv packet protocol match NAT-T type
+    - use NAT-OA (when available) to quickly fix TCP/UDP checksum
+    - fix IP checksum in ipsec_tunnel before sending it
+    - virtual IP management
+    - better connection handling/lookup
+    - new params (--nat_traversal, --keep_alive, --virtual_private) for pluto
+    - NAT-D hash use negociated hash algorithm (instead of MD5)
+
+  o Version 0.3
+    - FreeS/WAN 1.98b, X509 0.9.14, algo 0.8.0
+    - ESPinUDP patch now in klips/patches2.2 and klips/patches2.3
+    - bug when freeswan was initiator (zero cookie)
+    - correctly work with PSK
+    - draft-ietf-nat-t-ike-02/03 (floating port)
+    - expired NAT mappings recovering
+    - various bugfixes, improvements
+
+  o Version 0.4
+    - ipsec_rcv fix for Linux 2.2.xx
+    - klips/utils/Makefile fix (for manual keying)
+    - connection lookup improvement
+    - force_keepalive keyword in ipsec.conf
+      (SafeNet has been reported to not send keep alive packets)
+    - no more nested functions (reported to have problems with Openwall)
+    - SSH Sentinel 1.4 VID
+
+  o Version 0.5
+    - rewrote NAT-T host_pair/connection handling
+    - rewrote port change handling (addr change not handle)
+    - update kernel SA when port change is detected
+    - NAT-T debug messages using pluto debug functions (plutodebug=nat_t)
+    - port floating can be disable in config file (disable_port_floating=yes)
+    - Warning if IPSec-Passthrough NAT device is suspected and old drafts used
+    - accept most recent NAT-T VID instead of first one
+    - new ISAKMP VID (SSH Sentinel, esp-in-udp, Timestep)
+
+  o Version 0.5a
+    - fix bug that can block udp/4500 packets and create %hold state
+    - cosmetics
+
+  o Version 0.6
+    - new VIDs (FreeS/WAN, FRAGMENTATION)
+    - fix checksum in ipsec_tunnel.c when in transport mode
+    - support FreeS/WAN 2.0
+    - misc
+
diff -uNr freeswan-2.02.stock/lib/libfreeswan/Makefile freeswan-2.02/lib/libfreeswan/Makefile
--- freeswan-2.02.stock/lib/libfreeswan/Makefile	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/lib/libfreeswan/Makefile	2003-10-10 22:27:20.000000000 -0400
@@ -55,7 +55,7 @@
 #CFLAGS+= -W
 #CFLAGS+= -Wwrite-strings
 CFLAGS+= -Wbad-function-cast 
-
+CFLAGS+= -DNAT_TRAVERSAL
 
 
 ARFLAGS=crvs
diff -uNr freeswan-2.02.stock/linux/include/freeswan/ipsec_sa.h freeswan-2.02/linux/include/freeswan/ipsec_sa.h
--- freeswan-2.02.stock/linux/include/freeswan/ipsec_sa.h	2003-05-10 20:53:09.000000000 -0400
+++ freeswan-2.02/linux/include/freeswan/ipsec_sa.h	2003-10-10 22:27:20.000000000 -0400
@@ -182,6 +182,17 @@
 	__u64		ips_comp_ratio_dbytes;	/* decompressed (or uncompressed) bytes */
 #endif /* CONFIG_IPSEC_IPCOMP */
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	__u8        ips_natt_type;
+	__u8        ips_natt_reserved[3];
+	__u16       ips_natt_sport;
+	__u16       ips_natt_dport;
+ 
+	struct sockaddr *ips_natt_oa;
+	__u16		ips_natt_oa_size;
+	__u16		ips_natt_reserved2;
+#endif
+
 #if 0
 	__u32		ips_sens_dpd;
 	__u8		ips_sens_sens_level;
diff -uNr freeswan-2.02.stock/linux/include/freeswan.h freeswan-2.02/linux/include/freeswan.h
--- freeswan-2.02.stock/linux/include/freeswan.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/include/freeswan.h	2003-10-10 22:27:20.000000000 -0400
@@ -75,6 +75,16 @@
 #  define DEBUG_NO_STATIC static
 #endif /* CONFIG_IPSEC_DEBUG */
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL /* KERNEL ifdef */
+#ifndef NAT_TRAVERSAL
+#define NAT_TRAVERSAL
+#endif
+#endif
+#ifdef NAT_TRAVERSAL
+#define ESPINUDP_WITH_NON_IKE   1  /* draft-ietf-ipsec-nat-t-ike-00/01 */
+#define ESPINUDP_WITH_NON_ESP   2  /* draft-ietf-ipsec-nat-t-ike-02    */
+#endif
+
 /*
  * Basic data types for the address-handling functions.
  * ip_address and ip_subnet are supposed to be opaque types; do not
diff -uNr freeswan-2.02.stock/linux/include/pfkey.h freeswan-2.02/linux/include/pfkey.h
--- freeswan-2.02.stock/linux/include/pfkey.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/include/pfkey.h	2003-10-10 22:27:20.000000000 -0400
@@ -238,6 +238,21 @@
 		  uint8_t               ident_len,
 		  char*			ident_string);
 
+#ifdef NAT_TRAVERSAL
+#ifdef __KERNEL__
+extern int pfkey_nat_t_new_mapping(struct ipsec_sa *, struct sockaddr *, __u16);
+extern int pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
+extern int pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr);
+#endif /* __KERNEL__ */
+int
+pfkey_x_nat_t_type_build(struct sadb_ext**  pfkey_ext,
+            uint8_t         type);
+int
+pfkey_x_nat_t_port_build(struct sadb_ext**  pfkey_ext,
+            uint16_t         exttype,
+            uint16_t         port);
+#endif
+
 int
 pfkey_sens_build(struct sadb_ext**	pfkey_ext,
 		 uint32_t		dpd,
diff -uNr freeswan-2.02.stock/linux/include/pfkeyv2.h freeswan-2.02/linux/include/pfkeyv2.h
--- freeswan-2.02.stock/linux/include/pfkeyv2.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/include/pfkeyv2.h	2003-10-10 22:27:20.000000000 -0400
@@ -36,7 +36,12 @@
 #define SADB_X_ADDFLOW	14
 #define SADB_X_DELFLOW	15
 #define SADB_X_DEBUG	16
+#ifdef NAT_TRAVERSAL
+#define SADB_X_NAT_T_NEW_MAPPING  17
+#define SADB_MAX                  17
+#else
 #define SADB_MAX        16
+#endif
 
 struct sadb_msg {
   uint8_t sadb_msg_version;
@@ -203,6 +208,21 @@
   uint32_t sadb_x_debug_verbose;
   uint8_t sadb_x_debug_reserved[4];
 };
+
+#ifdef NAT_TRAVERSAL
+struct sadb_x_nat_t_type {
+  uint16_t sadb_x_nat_t_type_len;
+  uint16_t sadb_x_nat_t_type_exttype;
+  uint8_t sadb_x_nat_t_type_type;
+  uint8_t sadb_x_nat_t_type_reserved[3];
+};
+struct sadb_x_nat_t_port {
+  uint16_t sadb_x_nat_t_port_len;
+  uint16_t sadb_x_nat_t_port_exttype;
+  uint16_t sadb_x_nat_t_port_port;
+  uint16_t sadb_x_nat_t_port_reserved;
+};
+#endif
   
 /*
  * A protocol structure for passing through the transport level
@@ -246,7 +266,15 @@
 #define SADB_X_EXT_ADDRESS_DST_MASK   24
 #define SADB_X_EXT_DEBUG              25
 #define SADB_X_EXT_PROTOCOL           26
+#ifdef NAT_TRAVERSAL
+#define SADB_X_EXT_NAT_T_TYPE         27
+#define SADB_X_EXT_NAT_T_SPORT        28
+#define SADB_X_EXT_NAT_T_DPORT        29
+#define SADB_X_EXT_NAT_T_OA           30
+#define SADB_EXT_MAX                  30
+#else
 #define SADB_EXT_MAX                  26
+#endif
 
 /* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */
 #define SADB_X_EXT_ADDRESS_DELFLOW \
diff -uNr freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_build.c freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_build.c
--- freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_build.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_build.c	2003-10-10 22:27:20.000000000 -0400
@@ -452,6 +452,9 @@
 	case SADB_X_EXT_ADDRESS_DST_FLOW:
 	case SADB_X_EXT_ADDRESS_SRC_MASK:
 	case SADB_X_EXT_ADDRESS_DST_MASK:
+#ifdef NAT_TRAVERSAL
+	case SADB_X_EXT_NAT_T_OA:
+#endif
 		break;
 	default:
 		DEBUGGING( 
@@ -1135,6 +1138,99 @@
 	return error;
 }
 
+#ifdef NAT_TRAVERSAL
+int
+pfkey_x_nat_t_type_build(struct sadb_ext**	pfkey_ext,
+		    uint8_t         type)
+{
+	int error = 0;
+	int i;
+	struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext;
+
+	DEBUGGING(
+		"pfkey_x_nat_t_type_build:\n");
+	/* sanity checks... */
+	if(pfkey_x_nat_t_type) {
+		DEBUGGING(
+			"pfkey_x_nat_t_type_build: "
+			"why is pfkey_x_nat_t_type already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+	
+	DEBUGGING(
+		"pfkey_x_nat_t_type_build: "
+		"type=%d\n", type);
+
+	if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*)
+	     MALLOC(sizeof(struct sadb_x_nat_t_type)))) {
+		DEBUGGING(
+			"pfkey_x_nat_t_type_build: "
+			"memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	
+	pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN;
+	pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+	pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type;
+	for(i=0; i<3; i++) {
+		pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0;
+	}
+
+errlab:
+	return error;
+}
+int
+pfkey_x_nat_t_port_build(struct sadb_ext**	pfkey_ext,
+		    uint16_t         exttype,
+		    uint16_t         port)
+{
+	int error = 0;
+	struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext;
+
+	DEBUGGING(
+		"pfkey_x_nat_t_port_build:\n");
+	/* sanity checks... */
+	if(pfkey_x_nat_t_port) {
+		DEBUGGING(
+			"pfkey_x_nat_t_port_build: "
+			"why is pfkey_x_nat_t_port already pointing to something?\n");
+		SENDERR(EINVAL);
+	}
+	
+	switch(exttype) {	
+	case SADB_X_EXT_NAT_T_SPORT:
+	case SADB_X_EXT_NAT_T_DPORT:
+		break;
+	default:
+		DEBUGGING( 
+			"pfkey_nat_t_port_build: "
+			"unrecognised ext_type=%d.\n", 
+			exttype); 
+		SENDERR(EINVAL); 
+	}
+
+	DEBUGGING(
+		"pfkey_x_nat_t_port_build: "
+		"ext=%d, port=%d\n", exttype, port);
+
+	if(!(*pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*)
+	     MALLOC(sizeof(struct sadb_x_nat_t_port)))) {
+		DEBUGGING(
+			"pfkey_x_nat_t_port_build: "
+			"memory allocation failed\n");
+		SENDERR(ENOMEM);
+	}
+	
+	pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN;
+	pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype;
+	pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port;
+	pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0;
+
+errlab:
+	return error;
+}
+#endif
+
 int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext,
 			   uint8_t protocol)
 {
diff -uNr freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_debug.c freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_debug.c
--- freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_debug.c	2002-09-20 01:01:26.000000000 -0400
+++ freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_debug.c	2003-10-10 22:27:20.000000000 -0400
@@ -80,6 +80,12 @@
   "X-source-mask",                /* SADB_X_EXT_ADDRESS_SRC_MASK   23 */
   "X-dest-mask",                  /* SADB_X_EXT_ADDRESS_DST_MASK   24 */
   "X-set-debug",                  /* SADB_X_EXT_DEBUG              25 */
+#ifdef NAT_TRAVERSAL
+  "X-NAT-T-type",                 /* SADB_X_EXT_NAT_T_TYPE         26 */
+  "X-NAT-T-sport",                /* SADB_X_EXT_NAT_T_SPORT        27 */
+  "X-NAT-T-dport",                /* SADB_X_EXT_NAT_T_DPORT        28 */
+  "X-NAT-T-OA",                   /* SADB_X_EXT_NAT_T_OA           29 */
+#endif
 };
 
 const char *
diff -uNr freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_ext_bits.c freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_ext_bits.c
--- freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_ext_bits.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_ext_bits.c	2003-10-10 22:27:20.000000000 -0400
@@ -89,6 +89,10 @@
 | 1<<SADB_EXT_IDENTITY_SRC
 | 1<<SADB_EXT_IDENTITY_DST
 | 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
 ,
 /* SADB_ADD */
 1<<SADB_EXT_RESERVED
@@ -103,6 +107,12 @@
 | 1<<SADB_EXT_IDENTITY_SRC
 | 1<<SADB_EXT_IDENTITY_DST
 | 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+#endif
 ,
 /* SADB_DELETE */
 1<<SADB_EXT_RESERVED
@@ -219,6 +229,16 @@
 /* SADB_X_DEBUG */
 1<<SADB_EXT_RESERVED
 | 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
 },
 
 /* REQUIRED IN */
@@ -354,6 +374,16 @@
 /* SADB_X_DEBUG */
 1<<SADB_EXT_RESERVED
 | 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
 }
 
 },
@@ -395,6 +425,12 @@
 | 1<<SADB_EXT_IDENTITY_SRC
 | 1<<SADB_EXT_IDENTITY_DST
 | 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+#endif
 ,
 /* SADB_DELETE */
 1<<SADB_EXT_RESERVED
@@ -536,6 +572,16 @@
 /* SADB_X_DEBUG */
 1<<SADB_EXT_RESERVED
 | 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
 },
 
 /* REQUIRED OUT */
@@ -677,6 +723,16 @@
 /* SADB_X_DEBUG */
 1<<SADB_EXT_RESERVED
 | 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
 }
 }
 };
diff -uNr freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_parse.c freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_parse.c
--- freeswan-2.02.stock/linux/lib/libfreeswan/pfkey_v2_parse.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/lib/libfreeswan/pfkey_v2_parse.c	2003-10-10 22:27:20.000000000 -0400
@@ -388,6 +388,9 @@
 	case SADB_X_EXT_ADDRESS_DST_FLOW:
 	case SADB_X_EXT_ADDRESS_SRC_MASK:
 	case SADB_X_EXT_ADDRESS_DST_MASK:
+#ifdef NAT_TRAVERSAL
+	case SADB_X_EXT_NAT_T_OA:
+#endif
 		break;
 	default:
 		DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, 
@@ -1154,6 +1157,19 @@
 	return error;
 }
 
+#ifdef NAT_TRAVERSAL
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext)
+{
+	return 0;
+}
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext)
+{
+	return 0;
+}
+#endif
+
 #define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME};
 
 DEFINEPARSER(pfkey_sa_parse);
@@ -1169,6 +1185,10 @@
 DEFINEPARSER(pfkey_x_satype_parse);
 DEFINEPARSER(pfkey_x_ext_debug_parse);
 DEFINEPARSER(pfkey_x_ext_protocol_parse);
+#ifdef NAT_TRAVERSAL
+DEFINEPARSER(pfkey_x_ext_nat_t_type_parse);
+DEFINEPARSER(pfkey_x_ext_nat_t_port_parse);
+#endif
 
 struct pf_key_ext_parsers_def *ext_default_parsers[]=
 {
@@ -1199,6 +1219,13 @@
 	&pfkey_address_parse_def,
 	&pfkey_x_ext_debug_parse_def,
 	&pfkey_x_ext_protocol_parse_def
+#ifdef NAT_TRAVERSAL
+	,
+	&pfkey_x_ext_nat_t_type_parse_def,
+	&pfkey_x_ext_nat_t_port_parse_def,
+	&pfkey_x_ext_nat_t_port_parse_def,
+	&pfkey_address_parse_def
+#endif
 };
 
 int
diff -uNr freeswan-2.02.stock/linux/net/include.net.sock.h.fs2_2.patch freeswan-2.02/linux/net/include.net.sock.h.fs2_2.patch
--- freeswan-2.02.stock/linux/net/include.net.sock.h.fs2_2.patch	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/linux/net/include.net.sock.h.fs2_2.patch	2003-10-10 22:27:20.000000000 -0400
@@ -0,0 +1,25 @@
+--- ./include/net/sock.h	Fri Nov  2 17:39:16 2001
++++ ./include/net/sock.h	Mon Jun 10 19:44:55 2002
+@@ -201,6 +201,12 @@
+ 	__u32	end_seq;
+ };
+ 
++#if 1
++struct udp_opt {
++	__u32 esp_in_udp;
++};
++#endif
++
+ struct tcp_opt {
+ 	int	tcp_header_len;	/* Bytes of tcp header to send		*/
+ 
+@@ -443,6 +449,9 @@
+ #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+ 		struct spx_opt		af_spx;
+ #endif /* CONFIG_SPX */
++#if 1
++		struct udp_opt 		af_udp;
++#endif
+ 
+ 	} tp_pinfo;
+ 
diff -uNr freeswan-2.02.stock/linux/net/include.net.sock.h.fs2_4.patch freeswan-2.02/linux/net/include.net.sock.h.fs2_4.patch
--- freeswan-2.02.stock/linux/net/include.net.sock.h.fs2_4.patch	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/linux/net/include.net.sock.h.fs2_4.patch	2003-10-10 22:27:20.000000000 -0400
@@ -0,0 +1,25 @@
+--- ./include/net/sock.h	2002/02/06 15:25:10	1.1
++++ ./include/net/sock.h	2002/05/22 12:14:56
+@@ -245,6 +245,12 @@
+ 	__u32	end_seq;
+ };
+ 
++#if 1
++struct udp_opt {
++	__u32 esp_in_udp;
++};
++#endif
++
+ struct tcp_opt {
+ 	int	tcp_header_len;	/* Bytes of tcp header to send		*/
+ 
+@@ -584,6 +590,9 @@
+ #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+ 		struct spx_opt		af_spx;
+ #endif /* CONFIG_SPX */
++#if 1
++		struct udp_opt 		af_udp;
++#endif
+ 
+ 	} tp_pinfo;
+ 
diff -uNr freeswan-2.02.stock/linux/net/ipsec/Config.in freeswan-2.02/linux/net/ipsec/Config.in
--- freeswan-2.02.stock/linux/net/ipsec/Config.in	2002-04-24 03:36:26.000000000 -0400
+++ freeswan-2.02/linux/net/ipsec/Config.in	2003-10-10 22:27:20.000000000 -0400
@@ -33,6 +33,8 @@
 
 bool '   IPSEC Debugging Option' CONFIG_IPSEC_DEBUG
 
+bool '   IPSEC NAT-Traversal' CONFIG_IPSEC_NAT_TRAVERSAL
+
 #
 #
 # $Log: Config.in,v $
diff -uNr freeswan-2.02.stock/linux/net/ipsec/defconfig freeswan-2.02/linux/net/ipsec/defconfig
--- freeswan-2.02.stock/linux/net/ipsec/defconfig	2002-04-24 03:36:27.000000000 -0400
+++ freeswan-2.02/linux/net/ipsec/defconfig	2003-10-10 22:27:20.000000000 -0400
@@ -51,6 +51,9 @@
 # To enable userspace-switchable KLIPS debugging, say 'y'.
 CONFIG_IPSEC_DEBUG=y
 
+# NAT Traversal
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+
 #
 #
 # $Log: defconfig,v $
diff -uNr freeswan-2.02.stock/linux/net/ipsec/ipsec_rcv.c freeswan-2.02/linux/net/ipsec/ipsec_rcv.c
--- freeswan-2.02.stock/linux/net/ipsec/ipsec_rcv.c	2003-02-05 21:21:34.000000000 -0500
+++ freeswan-2.02/linux/net/ipsec/ipsec_rcv.c	2003-10-10 22:27:20.000000000 -0400
@@ -81,6 +81,10 @@
 
 #include "freeswan/ipsec_proto.h"
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#include <linux/udp.h>
+#endif
+
 #ifdef CONFIG_IPSEC_DEBUG
 int debug_ah = 0;
 int debug_esp = 0;
@@ -266,6 +270,12 @@
 			struct ipcomphdr *compp;
 		} ipcompstuff;
 	} protostuff;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	__u16 natt_len;
+	__u16 natt_sport;
+	__u16 natt_dport;
+	__u8 natt_type;
+#endif
 };
 
 struct xform_functions {
@@ -957,6 +967,40 @@
 		return IPSEC_RCV_SAIDNOTLIVE;
 	}
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if ((irs->natt_type) &&
+		( (irs->ipp->saddr != (((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr)) ||
+		  (irs->natt_sport != newipsp->ips_natt_sport)
+		)) {
+		struct sockaddr sipaddr;
+		/** Advertise NAT-T addr change to pluto **/
+		sipaddr.sa_family = AF_INET;
+		((struct sockaddr_in*)&sipaddr)->sin_addr.s_addr = irs->ipp->saddr;
+		((struct sockaddr_in*)&sipaddr)->sin_port = htons(irs->natt_sport);
+		pfkey_nat_t_new_mapping(newipsp, &sipaddr, irs->natt_sport);
+		/**
+		 * Then allow or block packet depending on
+		 * sysctl_ipsec_inbound_policy_check.
+		 *
+		 * In all cases, pluto will update SA if new mapping is
+		 * accepted.
+		 */
+		if (sysctl_ipsec_inbound_policy_check) {
+			KLIPS_PRINT(debug_rcv,
+				"klips_debug:ipsec_rcv: "
+				"SA:%s, src=%s:%u of pkt does not agree with expected "
+				"SA source address policy (pluto has been informed).\n",
+				irs->sa_len ? irs->sa : " (error)",
+				irs->ipsaddr_txt, irs->natt_sport);
+			if(irs->stats) {
+				irs->stats->rx_dropped++;
+			}
+			ipsec_sa_put(newipsp);
+			return IPSEC_RCV_FAILEDINBOUND;
+		}
+	}
+#endif
+
 	if(sysctl_ipsec_inbound_policy_check) {
 		if(irs->ipp->saddr != ((struct sockaddr_in*)(newipsp->ips_addr_s))->sin_addr.s_addr) {
 			KLIPS_PRINT(debug_rcv,
@@ -1009,6 +1053,24 @@
 		 * we just found matched the back pointer. But, we won't do this check anymore,
 		 * because we want to be able to nest SAs
 		 */
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+		KLIPS_PRINT(debug_rcv,
+			"klips_debug:ipsec_rcv: "
+			"natt_type=%u tdbp->ips_natt_type=%u : %s\n",
+			irs->natt_type, newipsp->ips_natt_type,
+			(irs->natt_type==newipsp->ips_natt_type)?"ok":"bad");
+		if (irs->natt_type != newipsp->ips_natt_type) {
+			KLIPS_PRINT(debug_rcv,
+				    "klips_debug:ipsec_rcv: "
+				    "SA:%s does not agree with expected NAT-T policy.\n",
+				    irs->sa_len ? irs->sa : " (error)");
+			if(irs->stats) {
+				irs->stats->rx_dropped++;
+			}
+			ipsec_sa_put(newipsp);
+			return IPSEC_RCV_FAILEDINBOUND;
+		}
+#endif
 	}
 
 	/* okay, SA checks out, so free any previous SA, and record a new one */
@@ -1365,6 +1427,76 @@
 		goto rcvleave;
 	}
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if (skb->sk && skb->nh.iph && skb->nh.iph->protocol==IPPROTO_UDP) {
+		/**
+		 * Packet comes from udp_queue_rcv_skb so it is already defrag,
+		 * checksum verified, ... (ie safe to use)
+		 *
+		 * If the packet is not for us, return -1 and udp_queue_rcv_skb
+		 * will continue to handle it (do not kfree skb !!).
+		 */
+		struct udp_opt *tp =  &(skb->sk->tp_pinfo.af_udp);
+		struct iphdr *ip = (struct iphdr *)skb->nh.iph;
+		struct udphdr *udp = (struct udphdr *)((__u32 *)ip+ip->ihl);
+		__u8 *udpdata = (__u8 *)udp + sizeof(struct udphdr);
+		__u32 *udpdata32 = (__u32 *)udpdata;
+
+		irs.natt_sport = ntohs(udp->source);
+		irs.natt_dport = ntohs(udp->dest);
+
+		KLIPS_PRINT(debug_rcv,
+		    "klips_debug:ipsec_rcv: "
+		    "suspected ESPinUDP packet (NAT-Traversal) [%d].\n",
+			tp->esp_in_udp);
+		KLIPS_IP_PRINT(debug_rcv, ip);
+
+		if (udpdata < skb->tail) {
+			unsigned int len = skb->tail - udpdata;
+			if ((len==1) && (udpdata[0]==0xff)) {
+				KLIPS_PRINT(debug_rcv,
+				    "klips_debug:ipsec_rcv: "
+					/* not IPv6 compliant message */
+				    "NAT-keepalive from %d.%d.%d.%d.\n", NIPQUAD(ip->saddr));
+				goto rcvleave;
+			}
+			else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_IKE) &&
+				(len > (2*sizeof(__u32) + sizeof(struct esp))) &&
+				(udpdata32[0]==0) && (udpdata32[1]==0) ) {
+				/* ESP Packet with Non-IKE header */
+				KLIPS_PRINT(debug_rcv, 
+					"klips_debug:ipsec_rcv: "
+					"ESPinUDP pkt with Non-IKE - spi=0x%x\n",
+					udpdata32[2]);
+				irs.natt_type = ESPINUDP_WITH_NON_IKE;
+				irs.natt_len = sizeof(struct udphdr)+(2*sizeof(__u32));
+			}
+			else if ( (tp->esp_in_udp == ESPINUDP_WITH_NON_ESP) &&
+				(len > sizeof(struct esp)) &&
+				(udpdata32[0]!=0) ) {
+				/* ESP Packet without Non-ESP header */
+				irs.natt_type = ESPINUDP_WITH_NON_ESP;
+				irs.natt_len = sizeof(struct udphdr);
+				KLIPS_PRINT(debug_rcv, 
+					"klips_debug:ipsec_rcv: "
+					"ESPinUDP pkt without Non-ESP - spi=0x%x\n",
+					udpdata32[0]);
+			}
+			else {
+				KLIPS_PRINT(debug_rcv,
+				    "klips_debug:ipsec_rcv: "
+					"IKE packet - not handled here\n");
+				MOD_DEC_USE_COUNT;
+				return -1;
+			}
+		}
+		else {
+			MOD_DEC_USE_COUNT;
+			return -1;
+		}
+	}
+#endif
+
 #ifdef IPH_is_SKB_PULLED
 	/* In Linux 2.4.4, the IP header has been skb_pull()ed before the
 	   packet is passed to us. So we'll skb_push() to get back to it. */
@@ -1425,6 +1557,50 @@
 	}
 #endif /* IP_FRAGMENT_LINEARIZE */
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if (irs.natt_len) {
+		/**
+		 * Now, we are sure packet is ESPinUDP. Remove natt_len bytes from
+		 * packet and modify protocol to ESP.
+		 */
+		if (((unsigned char *)skb->data > (unsigned char *)skb->nh.iph) &&
+			((unsigned char *)skb->nh.iph > (unsigned char *)skb->head)) {
+			unsigned int _len = (unsigned char *)skb->data -
+				(unsigned char *)skb->nh.iph;
+			KLIPS_PRINT(debug_rcv,
+				"klips_debug:ipsec_rcv: adjusting skb: skb_push(%u)\n",
+				_len);
+			skb_push(skb, _len);
+		}
+		KLIPS_PRINT(debug_rcv,
+		    "klips_debug:ipsec_rcv: "
+			"removing %d bytes from ESPinUDP packet\n", irs.natt_len);
+		ipp = (struct iphdr *)skb->data;
+		irs.iphlen = ipp->ihl << 2;
+		ipp->tot_len = htons(ntohs(ipp->tot_len) - irs.natt_len);
+		if (skb->len < irs.iphlen + irs.natt_len) {
+			printk(KERN_WARNING
+		       "klips_error:ipsec_rcv: "
+		       "ESPinUDP packet is too small (%d < %d+%d). "
+			   "This should never happen, please report.\n",
+		       (int)(skb->len), irs.iphlen, irs.natt_len);
+			goto rcvleave;
+		}
+		memmove(skb->data + irs.natt_len, skb->data, irs.iphlen);
+		skb_pull(skb, irs.natt_len);
+
+		/* update nh.iph */
+		ipp = skb->nh.iph = (struct iphdr *)skb->data;
+
+		/* modify protocol */
+		ipp->protocol = IPPROTO_ESP;
+
+		skb->sk = NULL;
+
+		KLIPS_IP_PRINT(debug_rcv, skb->nh.iph);
+	}
+#endif
+
 	ipp = skb->nh.iph;
 	ipsaddr.s_addr = ipp->saddr;
 	addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
@@ -1590,6 +1766,91 @@
 	}
 #endif /* CONFIG_IPSEC_IPCOMP */
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if ((irs.natt_type) && (ipp->protocol != IPPROTO_IPIP)) {
+		/**
+		 * NAT-Traversal and Transport Mode:
+		 *   we need to correct TCP/UDP checksum
+		 *
+		 * If we've got NAT-OA, we can fix checksum without recalculation.
+		 */
+		__u32 natt_oa = ipsp->ips_natt_oa ?
+			((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
+		__u16 pkt_len = skb->tail - (unsigned char *)ipp;
+		__u16 data_len = pkt_len - (ipp->ihl << 2);
+
+		switch (ipp->protocol) {
+			case IPPROTO_TCP:
+				if (data_len >= sizeof(struct tcphdr)) {
+					struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ipp+ipp->ihl);
+					if (natt_oa) {
+						__u32 buff[2] = { ~natt_oa, ipp->saddr };
+						KLIPS_PRINT(debug_rcv,
+				    		"klips_debug:ipsec_rcv: "
+							"NAT-T & TRANSPORT: "
+							"fix TCP checksum using NAT-OA\n");
+						tcp->check = csum_fold(
+							csum_partial((unsigned char *)buff, sizeof(buff),
+							tcp->check^0xffff));
+					}
+					else {
+						KLIPS_PRINT(debug_rcv,
+			    			"klips_debug:ipsec_rcv: "
+							"NAT-T & TRANSPORT: recalc TCP checksum\n");
+						if (pkt_len > (ntohs(ipp->tot_len)))
+							data_len -= (pkt_len - ntohs(ipp->tot_len));
+						tcp->check = 0;
+						tcp->check = csum_tcpudp_magic(ipp->saddr, ipp->daddr,
+							data_len, IPPROTO_TCP,
+							csum_partial((unsigned char *)tcp, data_len, 0));
+					}
+				}
+				else {
+					KLIPS_PRINT(debug_rcv,
+			    		"klips_debug:ipsec_rcv: "
+						"NAT-T & TRANSPORT: can't fix TCP checksum\n");
+				}
+				break;
+			case IPPROTO_UDP:
+				if (data_len >= sizeof(struct udphdr)) {
+					struct udphdr *udp = (struct udphdr *)((__u32 *)ipp+ipp->ihl);
+					if (udp->check == 0) {
+						KLIPS_PRINT(debug_rcv,
+				    		"klips_debug:ipsec_rcv: "
+							"NAT-T & TRANSPORT: UDP checksum already 0\n");
+					}
+					else if (natt_oa) {
+						__u32 buff[2] = { ~natt_oa, ipp->saddr };
+						KLIPS_PRINT(debug_rcv,
+				    		"klips_debug:ipsec_rcv: "
+							"NAT-T & TRANSPORT: "
+							"fix UDP checksum using NAT-OA\n");
+						udp->check = csum_fold(
+							csum_partial((unsigned char *)buff, sizeof(buff),
+							udp->check^0xffff));
+					}
+					else {
+						KLIPS_PRINT(debug_rcv,
+				    		"klips_debug:ipsec_rcv: "
+							"NAT-T & TRANSPORT: zero UDP checksum\n");
+						udp->check = 0;
+					}
+				}
+				else {
+					KLIPS_PRINT(debug_rcv,
+			    		"klips_debug:ipsec_rcv: "
+						"NAT-T & TRANSPORT: can't fix UDP checksum\n");
+				}
+				break;
+			default:
+				KLIPS_PRINT(debug_rcv,
+			    	"klips_debug:ipsec_rcv: "
+					"NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
+				break;
+		}
+	}
+#endif
+
 	/*
 	 * XXX this needs to be locked from when it was first looked
 	 * up in the decapsulation loop.  Perhaps it is better to put
diff -uNr freeswan-2.02.stock/linux/net/ipsec/ipsec_sa.c freeswan-2.02/linux/net/ipsec/ipsec_sa.c
--- freeswan-2.02.stock/linux/net/ipsec/ipsec_sa.c	2003-02-05 20:50:34.000000000 -0500
+++ freeswan-2.02/linux/net/ipsec/ipsec_sa.c	2003-10-10 22:27:20.000000000 -0400
@@ -966,6 +966,14 @@
 	}
 	ips->ips_addr_p = NULL;
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if(ips->ips_natt_oa) {
+		memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
+		kfree(ips->ips_natt_oa);
+	}
+	ips->ips_natt_oa = NULL;
+#endif
+
 	if(ips->ips_key_a != NULL) {
 		memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
 		kfree(ips->ips_key_a);
diff -uNr freeswan-2.02.stock/linux/net/ipsec/ipsec_tunnel.c freeswan-2.02/linux/net/ipsec/ipsec_tunnel.c
--- freeswan-2.02.stock/linux/net/ipsec/ipsec_tunnel.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/net/ipsec/ipsec_tunnel.c	2003-10-10 22:40:23.000000000 -0400
@@ -116,6 +116,10 @@
 #endif
 
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#include <linux/udp.h>
+#endif
+
 static __u32 zeroes[64];
 
 #ifdef CONFIG_IPSEC_DEBUG
@@ -662,6 +666,12 @@
 	int error;
 	uint32_t eroute_pid;
 	struct ipsec_sa ips;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+        uint8_t natt_type = 0, natt_head = 0;
+        uint16_t natt_sport = 0, natt_dport = 0;
+#endif  
+
 };
 
 struct xform_functions {
@@ -739,7 +749,12 @@
 	    && (!ixs->eroute
 		|| ixs->iph->daddr == ixs->eroute->er_said.dst.s_addr
 		|| INADDR_ANY == ixs->eroute->er_said.dst.s_addr)
-	    && (ixs->sport == 500)) {
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+            && ((ixs->sport == 500) || (ixs->sport == 4500))
+#else
+            && (ixs->sport == 500)
+#endif
+            ) {
 		/* Whatever the eroute, this is an IKE message
 		 * from us (i.e. not being forwarded).
 		 * Furthermore, if there is a tunnel eroute,
@@ -894,6 +909,26 @@
 			return IPSEC_XMIT_ESP_BADALG;
 		}		
 		tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+                if ((ipsp->ips_natt_type) && (!natt_type)) {
+			natt_type = ipsp->ips_natt_type;
+			natt_sport = ipsp->ips_natt_sport;
+			natt_dport = ipsp->ips_natt_dport;
+			switch (natt_type) {
+				case ESPINUDP_WITH_NON_IKE:
+					natt_head = sizeof(struct udphdr)+(2*sizeof(__u32));
+					break;
+				case ESPINUDP_WITH_NON_ESP:
+					natt_head = sizeof(struct udphdr);
+					break;
+				default:
+					natt_head = 0;
+					break;
+			}
+			tailroom += natt_head;
+		}
+#endif
 		tailroom += authlen;
 		break;
 #endif /* !CONFIG_IPSEC_ESP */
@@ -1693,6 +1728,85 @@
 		}
 	}
 #endif /* MSS_HACK */
+  
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if ((natt_type) && (outgoing_said.proto != IPPROTO_IPIP)) {
+		/**
+		 * NAT-Traversal and Transport Mode:
+		 *   we need to correct TCP/UDP checksum
+		 *
+		 * If we've got NAT-OA, we can fix checksum without recalculation.
+		 * If we don't we can zero udp checksum.
+		 */
+		__u32 natt_oa = ipsp->ips_natt_oa ?
+			((struct sockaddr_in*)(ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
+		__u16 pkt_len = skb->tail - (unsigned char *)iph;
+		__u16 data_len = pkt_len - (iph->ihl << 2);
+		switch (iph->protocol) {
+			case IPPROTO_TCP:
+				if (data_len >= sizeof(struct tcphdr)) {
+ 					struct tcphdr *tcp = (struct tcphdr *)((__u32 *)iph+iph->ihl);
+					if (natt_oa) {
+						__u32 buff[2] = { ~iph->daddr, natt_oa };
+						KLIPS_PRINT(debug_tunnel,
+							"klips_debug:ipsec_tunnel_start_xmit: "
+							"NAT-T & TRANSPORT: "
+							"fix TCP checksum using NAT-OA\n");
+						tcp->check = csum_fold(
+							csum_partial((unsigned char *)buff, sizeof(buff),
+							tcp->check^0xffff));
+					}
+					else {
+						KLIPS_PRINT(debug_tunnel,
+							"klips_debug:ipsec_tunnel_start_xmit: "
+							"NAT-T & TRANSPORT: do not recalc TCP checksum\n");
+					}
+				}
+				else {
+					KLIPS_PRINT(debug_tunnel,
+						"klips_debug:ipsec_tunnel_start_xmit: "
+						"NAT-T & TRANSPORT: can't fix TCP checksum\n");
+				}
+				break;
+			case IPPROTO_UDP:
+				if (data_len >= sizeof(struct udphdr)) {
+					struct udphdr *udp = (struct udphdr *)((__u32 *)iph+iph->ihl);
+					if (udp->check == 0) {
+						KLIPS_PRINT(debug_tunnel,
+							"klips_debug:ipsec_tunnel_start_xmit: "
+							"NAT-T & TRANSPORT: UDP checksum already 0\n");
+					}
+					else if (natt_oa) {
+						__u32 buff[2] = { ~iph->daddr, natt_oa };
+						KLIPS_PRINT(debug_tunnel,
+							"klips_debug:ipsec_tunnel_start_xmit: "
+							"NAT-T & TRANSPORT: "
+							"fix UDP checksum using NAT-OA\n");
+						udp->check = csum_fold(
+							csum_partial((unsigned char *)buff, sizeof(buff),
+							udp->check^0xffff));
+					}
+					else {
+						KLIPS_PRINT(debug_tunnel,
+							"klips_debug:ipsec_tunnel_start_xmit: "
+							"NAT-T & TRANSPORT: zero UDP checksum\n");
+						udp->check = 0;
+					}
+				}
+				else {
+					KLIPS_PRINT(debug_tunnel,
+						"klips_debug:ipsec_tunnel_start_xmit: "
+						"NAT-T & TRANSPORT: can't fix UDP checksum\n");
+				}
+				break;
+			default:
+				KLIPS_PRINT(debug_tunnel,
+					"klips_debug:ipsec_tunnel_start_xmit: "
+					"NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
+				break;
+		}
+	}
+#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
 
 	if(!ixs->hard_header_stripped) {
 		KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
@@ -2062,6 +2176,48 @@
 			}
 		}
 	}
+
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+      if (natt_type && natt_head) {
+              struct iphdr *ipp = skb->nh.iph;
+              struct udphdr *udp;
+              KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
+                      "klips_debug:ipsec_tunnel_start_xmit: "
+                      "encapsuling packet into UDP (NAT-Traversal)\n");
+              iphlen = ipp->ihl << 2;
+              ipp->tot_len =
+                      htons(ntohs(ipp->tot_len) + natt_head);
+              if(skb_tailroom(skb) < natt_head) {
+                      printk(KERN_WARNING "klips_error:ipsec_tunnel_start_xmit: "
+                              "tried to skb_put %d, %d available. "
+                              "This should never happen, please report.\n",
+                              natt_head,
+                              skb_tailroom(skb));
+                      stats->tx_errors++;
+                      goto cleanup;  
+              }
+              skb_put(skb, natt_head);
+              udp = (struct udphdr *)((char *)ipp + iphlen);
+              /* move ESP hdr after UDP hdr */
+              memmove((void *)((char *)udp + natt_head),
+                      (void *)(udp),
+                      ntohs(ipp->tot_len) - iphlen - natt_head);
+              /* clear UDP & Non-IKE Markers (if any) */
+              memset(udp, 0, natt_head); 
+              /* fill UDP with usefull informations ;-) */
+              udp->source = htons(natt_sport);
+              udp->dest = htons(natt_dport);
+              udp->len = htons(ntohs(ipp->tot_len) - iphlen);
+              /* set protocol */
+              ipp->protocol = IPPROTO_UDP;
+              /* fix IP checksum */ 
+              ipp->check = 0;
+              ipp->check = ip_fast_csum((unsigned char *)ipp, ipp->ihl);
+      }
+#endif
+
+
+
  bypass:
 	KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
 		    "klips_debug:ipsec_tunnel_start_xmit: "
diff -uNr freeswan-2.02.stock/linux/net/ipsec/pfkey_v2_ext_process.c freeswan-2.02/linux/net/ipsec/pfkey_v2_ext_process.c
--- freeswan-2.02.stock/linux/net/ipsec/pfkey_v2_ext_process.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/net/ipsec/pfkey_v2_ext_process.c	2003-10-10 22:27:20.000000000 -0400
@@ -354,6 +354,15 @@
 		sap = (unsigned char **)&(extr->eroute->er_emask.sen_ip_dst);
 		portp = &(extr->eroute->er_emask.sen_dport);
 		break;
+#ifdef NAT_TRAVERSAL
+	case SADB_X_EXT_NAT_T_OA:
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:pfkey_address_process: "
+			    "found NAT-OA address.\n");
+		sap = (unsigned char **)&(extr->ips->ips_natt_oa);
+		extr->ips->ips_natt_oa_size = saddr_len;
+		break;
+#endif
 	default:
 		KLIPS_PRINT(debug_pfkey,
 			    "klips_debug:pfkey_address_process: "
@@ -367,6 +376,9 @@
 	case SADB_EXT_ADDRESS_DST:
 	case SADB_EXT_ADDRESS_PROXY:
 	case SADB_X_EXT_ADDRESS_DST2:
+#ifdef NAT_TRAVERSAL
+	case SADB_X_EXT_NAT_T_OA:
+#endif
 		KLIPS_PRINT(debug_pfkey,
 			    "klips_debug:pfkey_address_process: "
 			    "allocating %d bytes for saddr.\n",
@@ -681,6 +693,93 @@
 	return error;
 }
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+int
+pfkey_x_nat_t_type_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+	int error = 0;
+	struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)pfkey_ext;
+
+	if(!pfkey_x_nat_t_type) {
+		printk("klips_debug:pfkey_x_nat_t_type_process: "
+		       "null pointer passed in\n");
+		SENDERR(EINVAL);
+	}
+
+	KLIPS_PRINT(debug_pfkey,
+		    "klips_debug:pfkey_x_nat_t_type_process: %d.\n",
+			pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
+
+	if(!extr || !extr->ips) {
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:pfkey_nat_t_type_process: "
+			    "extr or extr->ips is NULL, fatal\n");
+		SENDERR(EINVAL);
+	}
+
+	switch(pfkey_x_nat_t_type->sadb_x_nat_t_type_type) {
+		case ESPINUDP_WITH_NON_IKE: /* with Non-IKE */
+		case ESPINUDP_WITH_NON_ESP: /* with Non-ESP */
+			extr->ips->ips_natt_type = pfkey_x_nat_t_type->sadb_x_nat_t_type_type;
+			break;
+		default:
+			KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:pfkey_x_nat_t_type_process: "
+			    "unknown type %d.\n",
+			    pfkey_x_nat_t_type->sadb_x_nat_t_type_type);
+			SENDERR(EINVAL);
+			break;
+	}
+
+errlab:
+	return error;
+}
+
+int
+pfkey_x_nat_t_port_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
+{
+	int error = 0;
+	struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)pfkey_ext;
+
+	if(!pfkey_x_nat_t_port) {
+		printk("klips_debug:pfkey_x_nat_t_port_process: "
+		       "null pointer passed in\n");
+		SENDERR(EINVAL);
+	}
+
+	KLIPS_PRINT(debug_pfkey,
+		    "klips_debug:pfkey_x_nat_t_port_process: %d/%d.\n",
+			pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype,
+			pfkey_x_nat_t_port->sadb_x_nat_t_port_port);
+
+	if(!extr || !extr->ips) {
+		KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:pfkey_nat_t_type_process: "
+			    "extr or extr->ips is NULL, fatal\n");
+		SENDERR(EINVAL);
+	}
+
+	switch(pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype) {
+		case SADB_X_EXT_NAT_T_SPORT:
+			extr->ips->ips_natt_sport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
+			break;
+		case SADB_X_EXT_NAT_T_DPORT:
+			extr->ips->ips_natt_dport = pfkey_x_nat_t_port->sadb_x_nat_t_port_port;
+			break;
+		default:
+			KLIPS_PRINT(debug_pfkey,
+			    "klips_debug:pfkey_x_nat_t_port_process: "
+			    "unknown exttype %d.\n",
+			    pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype);
+			SENDERR(EINVAL);
+			break;
+	}
+
+errlab:
+	return error;
+}
+#endif
+
 int
 pfkey_x_debug_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr)
 {
diff -uNr freeswan-2.02.stock/linux/net/ipsec/pfkey_v2_parser.c freeswan-2.02/linux/net/ipsec/pfkey_v2_parser.c
--- freeswan-2.02.stock/linux/net/ipsec/pfkey_v2_parser.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/linux/net/ipsec/pfkey_v2_parser.c	2003-10-10 22:27:21.000000000 -0400
@@ -886,6 +886,9 @@
 	struct sadb_msg *pfkey_reply = NULL;
 	struct socket_list *pfkey_socketsp;
 	uint8_t satype = ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype;
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	struct ipsec_sa *nat_t_ips_saved = NULL;
+#endif
 
 	KLIPS_PRINT(debug_pfkey,
 		    "klips_debug:pfkey_update_parse: .\n");
@@ -932,6 +935,33 @@
 		    sa_len ? sa : " (error)",
 		    extr->ips->ips_flags & EMT_INBOUND ? "in" : "out");
 	
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if (extr->ips->ips_natt_sport || extr->ips->ips_natt_dport) {
+		KLIPS_PRINT(debug_pfkey,
+			"klips_debug:pfkey_update_parse: only updating NAT-T ports "
+			"(%u:%u -> %u:%u)\n", 
+			ipsq->ips_natt_sport, ipsq->ips_natt_dport,
+			extr->ips->ips_natt_sport, extr->ips->ips_natt_dport);
+
+		if (extr->ips->ips_natt_sport) {
+			ipsq->ips_natt_sport = extr->ips->ips_natt_sport;
+			if (ipsq->ips_addr_s->sa_family == AF_INET) {
+				((struct sockaddr_in *)(ipsq->ips_addr_s))->sin_port = htons(extr->ips->ips_natt_sport);
+			}
+		}
+
+		if (extr->ips->ips_natt_dport) {
+			ipsq->ips_natt_dport = extr->ips->ips_natt_dport;
+			if (ipsq->ips_addr_d->sa_family == AF_INET) {
+				((struct sockaddr_in *)(ipsq->ips_addr_d))->sin_port = htons(extr->ips->ips_natt_dport);
+			}
+		}
+
+		nat_t_ips_saved = extr->ips;
+		extr->ips = ipsq;
+	}
+	else {
+#endif
 	/* XXX extr->ips->ips_rcvif = &(enc_softc[em->em_if].enc_if);*/
 	extr->ips->ips_rcvif = NULL;
 	if ((error = pfkey_ipsec_sa_init(extr->ips, extensions))) {
@@ -955,6 +985,9 @@
 			    sa_len ? sa : " (error)");
 		SENDERR(-error);
 	}
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	}
+#endif
 
 	spin_unlock_bh(&tdb_lock);
 	
@@ -1080,6 +1113,27 @@
 			    pfkey_socketsp->socketp);
 	}
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if (nat_t_ips_saved) {
+		/**
+		 * As we _really_ update existing SA, we keep tdbq and need to delete
+		 * parsed ips (nat_t_ips_saved, was extr->ips).
+		 *
+		 * goto errlab with extr->ips = nat_t_ips_saved will free it.
+		 */
+
+		extr->ips = nat_t_ips_saved;
+
+		error = 0;
+		KLIPS_PRINT(debug_pfkey,
+		    "klips_debug:pfkey_update_parse (NAT-T ports): "
+		    "successful for SA: %s\n",
+		    sa_len ? sa : " (error)");
+
+		goto errlab;
+	}
+#endif
+
 	if((error = ipsec_sa_add(extr->ips))) {
 		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_update_parse: "
 			    "failed to update the mature SA=%s with error=%d.\n",
@@ -2917,6 +2971,107 @@
 	return error;
 }
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+int
+pfkey_nat_t_new_mapping(struct ipsec_sa *ipsp, struct sockaddr *ipaddr,
+	__u16 sport)
+{
+	struct sadb_ext *extensions[SADB_EXT_MAX+1];
+	struct sadb_msg *pfkey_msg = NULL;
+	struct socket_list *pfkey_socketsp;
+	int error = 0;
+	uint8_t satype = (ipsp->ips_said.proto==IPPROTO_ESP) ? SADB_SATYPE_ESP : 0;
+
+	/* Construct SADB_X_NAT_T_NEW_MAPPING message */
+
+	pfkey_extensions_init(extensions);
+
+	if((satype == 0) || (satype > SADB_SATYPE_MAX)) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+			    "SAtype=%d unspecified or unknown.\n",
+			    satype);
+		SENDERR(EINVAL);
+	}
+
+	if(!(pfkey_registered_sockets[satype])) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+			    "no sockets registered for SAtype=%d(%s).\n",
+			    satype,
+			    satype2name(satype));
+		SENDERR(EPROTONOSUPPORT);
+	}
+
+	if (!(pfkey_safe_build
+		(error = pfkey_msg_hdr_build(&extensions[0], SADB_X_NAT_T_NEW_MAPPING,
+			satype, 0, ++pfkey_msg_seq, 0), extensions)
+		/* SA */
+		&& pfkey_safe_build
+		(error = pfkey_sa_build(&extensions[SADB_EXT_SA],
+			SADB_EXT_SA, ipsp->ips_said.spi, 0, 0, 0, 0, 0), extensions)
+		/* ADDRESS_SRC = old addr */
+		&& pfkey_safe_build
+		(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_SRC],
+			SADB_EXT_ADDRESS_SRC, ipsp->ips_said.proto, 0, ipsp->ips_addr_s),
+			extensions)
+		/* NAT_T_SPORT = old port */
+	    && pfkey_safe_build
+		(error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_SPORT],
+			SADB_X_EXT_NAT_T_SPORT, ipsp->ips_natt_sport), extensions)
+		/* ADDRESS_DST = new addr */
+		&& pfkey_safe_build
+		(error = pfkey_address_build(&extensions[SADB_EXT_ADDRESS_DST],
+			SADB_EXT_ADDRESS_DST, ipsp->ips_said.proto, 0, ipaddr), extensions)
+		/* NAT_T_DPORT = new port */
+	    && pfkey_safe_build
+		(error = pfkey_x_nat_t_port_build(&extensions[SADB_X_EXT_NAT_T_DPORT],
+			SADB_X_EXT_NAT_T_DPORT, sport), extensions)
+		)) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+			    "failed to build the nat_t_new_mapping message extensions\n");
+		SENDERR(-error);
+	}
+	
+	if ((error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_OUT))) {
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+			    "failed to build the nat_t_new_mapping message\n");
+		SENDERR(-error);
+	}
+
+	/* this should go to all registered sockets for that satype only */
+	for(pfkey_socketsp = pfkey_registered_sockets[satype];
+	    pfkey_socketsp;
+	    pfkey_socketsp = pfkey_socketsp->next) {
+		if((error = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_msg))) {
+			KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+				    "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p failed with error=%d.\n",
+				    satype,
+				    satype2name(satype),
+				    pfkey_socketsp->socketp,
+				    error);
+			SENDERR(-error);
+		}
+		KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_nat_t_new_mapping: "
+			    "sending up nat_t_new_mapping message for satype=%d(%s) to socket=%p succeeded.\n",
+			    satype,
+			    satype2name(satype),
+			    pfkey_socketsp->socketp);
+	}
+	
+ errlab:
+	if (pfkey_msg) {
+		pfkey_msg_free(&pfkey_msg);
+	}
+	pfkey_extensions_free(extensions);
+	return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_nat_t_new_mapping_parse(struct sock *sk, struct sadb_ext **extensions, struct pfkey_extracted_data* extr)
+{
+	/* SADB_X_NAT_T_NEW_MAPPING not used in kernel */
+	return -EINVAL;
+}
+#endif
 
 DEBUG_NO_STATIC int (*ext_processors[SADB_EXT_MAX+1])(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) =
 {
@@ -2947,6 +3102,13 @@
         pfkey_address_process,
 	pfkey_x_debug_process,
 	pfkey_x_protocol_process
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	,
+	pfkey_x_nat_t_type_process,
+	pfkey_x_nat_t_port_process,
+	pfkey_x_nat_t_port_process,
+	pfkey_address_process
+#endif
 };
 
 
@@ -2970,6 +3132,9 @@
 	pfkey_x_addflow_parse,
 	pfkey_x_delflow_parse,
 	pfkey_x_msg_debug_parse
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	, pfkey_x_nat_t_new_mapping_parse
+#endif
 };
 
 int
diff -uNr freeswan-2.02.stock/linux/net/ipv4/udp.c.fs2_2.patch freeswan-2.02/linux/net/ipv4/udp.c.fs2_2.patch
--- freeswan-2.02.stock/linux/net/ipv4/udp.c.fs2_2.patch	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/linux/net/ipv4/udp.c.fs2_2.patch	2003-10-10 22:27:21.000000000 -0400
@@ -0,0 +1,108 @@
+--- ./net/ipv4/udp.c	Sun Mar 25 18:37:41 2001
++++ ./net/ipv4/udp.c	Mon Jun 10 19:53:18 2002
+@@ -965,6 +965,9 @@
+ 
+ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++	struct udp_opt *tp =  &(sk->tp_pinfo.af_udp);
++#endif
+ 	/*
+ 	 *	Charge it to the socket, dropping if the queue is full.
+ 	 */
+@@ -982,6 +985,38 @@
+ 	}
+ #endif
+ 
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++	if (tp->esp_in_udp) {
++		/*
++		 * Set skb->sk and xmit packet to ipsec_rcv.
++		 *
++		 * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
++		 * restore skb->sk and fall back to sock_queue_rcv_skb
++		 */
++		struct inet_protocol *esp = NULL;
++
++#ifdef CONFIG_IPSEC_MODULE
++		for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
++			(esp) && (esp->protocol != IPPROTO_ESP);
++			esp = esp->next);
++#else
++		extern struct inet_protocol esp_protocol;
++		esp = &esp_protocol;
++#endif
++
++		if (esp && esp->handler) {
++			struct sock *sav_sk = skb->sk;
++			skb->sk = sk;
++			if (esp->handler(skb, 0) == 0) {
++				skb->sk = sav_sk;
++				/* not sure we might count ESPinUDP as UDP... */
++				udp_statistics.UdpInDatagrams++;
++				return 0;
++			}
++			skb->sk = sav_sk;
++		}
++	}
++#endif
+ 	if (sock_queue_rcv_skb(sk,skb)<0) {
+ 		udp_statistics.UdpInErrors++;
+ 		ip_statistics.IpInDiscards++;
+@@ -1165,6 +1200,44 @@
+ 	return(0);
+ }
+ 
++#if 1
++static int udp_setsockopt(struct sock *sk, int level, int optname,
++	char *optval, int optlen)
++{
++	struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++	int val;
++	int err = 0;
++
++	if (level != SOL_UDP)
++		return ip_setsockopt(sk, level, optname, optval, optlen);
++
++	if(optlen<sizeof(int))
++		return -EINVAL;
++
++	if (get_user(val, (int *)optval))
++		return -EFAULT;
++	
++	lock_sock(sk);
++
++	switch(optname) {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#ifndef UDP_ESPINUDP
++#define UDP_ESPINUDP 100
++#endif
++		case UDP_ESPINUDP:
++			tp->esp_in_udp = val;
++			break;
++#endif
++		default:
++			err = -ENOPROTOOPT;
++			break;
++	}
++
++	release_sock(sk);
++	return err;
++}
++#endif
++
+ struct proto udp_prot = {
+ 	(struct sock *)&udp_prot,	/* sklist_next */
+ 	(struct sock *)&udp_prot,	/* sklist_prev */
+@@ -1179,7 +1252,11 @@
+ 	NULL,				/* init */
+ 	NULL,				/* destroy */
+ 	NULL,				/* shutdown */
++#if 1
++	udp_setsockopt,			/* setsockopt */
++#else
+ 	ip_setsockopt,			/* setsockopt */
++#endif
+ 	ip_getsockopt,			/* getsockopt */
+ 	udp_sendmsg,			/* sendmsg */
+ 	udp_recvmsg,			/* recvmsg */
diff -uNr freeswan-2.02.stock/linux/net/ipv4/udp.c.fs2_4.patch freeswan-2.02/linux/net/ipv4/udp.c.fs2_4.patch
--- freeswan-2.02.stock/linux/net/ipv4/udp.c.fs2_4.patch	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/linux/net/ipv4/udp.c.fs2_4.patch	2003-10-10 22:27:21.000000000 -0400
@@ -0,0 +1,107 @@
+--- ./net/ipv4/udp.c	2002/02/26 14:54:22	1.2
++++ ./net/ipv4/udp.c	2002/05/22 12:14:58
+@@ -777,6 +777,9 @@
+ 
+ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++	struct udp_opt *tp =  &(sk->tp_pinfo.af_udp);
++#endif
+ 	/*
+ 	 *	Charge it to the socket, dropping if the queue is full.
+ 	 */
+@@ -794,6 +797,38 @@
+ 	}
+ #endif
+ 
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++	if (tp->esp_in_udp) {
++		/*
++		 * Set skb->sk and xmit packet to ipsec_rcv.
++		 *
++		 * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
++		 * restore skb->sk and fall back to sock_queue_rcv_skb
++		 */
++		struct inet_protocol *esp = NULL;
++
++#ifdef CONFIG_IPSEC_MODULE
++		for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
++			(esp) && (esp->protocol != IPPROTO_ESP);
++			esp = esp->next);
++#else
++		extern struct inet_protocol esp_protocol;
++		esp = &esp_protocol;
++#endif
++
++		if (esp && esp->handler) {
++			struct sock *sav_sk = skb->sk;
++			skb->sk = sk;
++			if (esp->handler(skb) == 0) {
++				skb->sk = sav_sk;
++				/* not sure we might count ESPinUDP as UDP... */
++				UDP_INC_STATS_BH(UdpInDatagrams);
++				return 0;
++			}
++			skb->sk = sav_sk;
++		}
++	}
++#endif
+ 	if (sock_queue_rcv_skb(sk,skb)<0) {
+ 		UDP_INC_STATS_BH(UdpInErrors);
+ 		IP_INC_STATS_BH(IpInDiscards);
+@@ -1010,13 +1045,55 @@
+ 	return len;
+ }
+ 
++#if 1
++static int udp_setsockopt(struct sock *sk, int level, int optname,
++	char *optval, int optlen)
++{
++	struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++	int val;
++	int err = 0;
++
++	if (level != SOL_UDP)
++		return ip_setsockopt(sk, level, optname, optval, optlen);
++
++	if(optlen<sizeof(int))
++		return -EINVAL;
++
++	if (get_user(val, (int *)optval))
++		return -EFAULT;
++	
++	lock_sock(sk);
++
++	switch(optname) {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#ifndef UDP_ESPINUDP
++#define UDP_ESPINUDP 100
++#endif
++		case UDP_ESPINUDP:
++			tp->esp_in_udp = val;
++			break;
++#endif
++		default:
++			err = -ENOPROTOOPT;
++			break;
++	}
++
++	release_sock(sk);
++	return err;
++}
++#endif
++
+ struct proto udp_prot = {
+  	name:		"UDP",
+ 	close:		udp_close,
+ 	connect:	udp_connect,
+ 	disconnect:	udp_disconnect,
+ 	ioctl:		udp_ioctl,
++#if 1
++	setsockopt:	udp_setsockopt,
++#else
+ 	setsockopt:	ip_setsockopt,
++#endif
+ 	getsockopt:	ip_getsockopt,
+ 	sendmsg:	udp_sendmsg,
+ 	recvmsg:	udp_recvmsg,
diff -uNr freeswan-2.02.stock/programs/Makefile.program freeswan-2.02/programs/Makefile.program
--- freeswan-2.02.stock/programs/Makefile.program	2003-06-29 17:34:49.000000000 -0400
+++ freeswan-2.02/programs/Makefile.program	2003-10-10 22:45:56.000000000 -0400
@@ -15,6 +15,7 @@
 #CFLAGS+= -W
 #CFLAGS+= -Wwrite-strings
 CFLAGS+= -Wbad-function-cast 
+CFLAGS+= -DNAT_TRAVERSAL
 
 # die if there are any warnings
 ifndef WERROR
diff -uNr freeswan-2.02.stock/programs/_confread/_confread.in freeswan-2.02/programs/_confread/_confread.in
--- freeswan-2.02.stock/programs/_confread/_confread.in	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/_confread/_confread.in	2003-10-10 22:45:56.000000000 -0400
@@ -154,6 +154,8 @@
 	good = good " fragicmp hidetos rp_filter uniqueids"
 	good = good " overridemtu"
 	good = good " nocrsend strictcrlpolicy crlcheckinterval"
+	good = good " nat_traversal keep_alive force_keepalive"
+	good = good " disable_port_floating virtual_private"
 	n = split(good, g)
 	for (i = 1; i <= n; i++)
 		goodnames["config:" g[i]] = 1
diff -uNr freeswan-2.02.stock/programs/_plutorun/_plutorun.in freeswan-2.02/programs/_plutorun/_plutorun.in
--- freeswan-2.02.stock/programs/_plutorun/_plutorun.in	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/_plutorun/_plutorun.in	2003-10-10 22:48:53.000000000 -0400
@@ -33,6 +33,11 @@
 	--debug)	plutodebug="$2" ; shift	;;
 	--uniqueids)	uniqueids="$2" ; shift	;;
 	--nocrsend)	nocrsend="$2" ; shift	;;
+        --nat_traversal)    nat_traversal="$2" ; shift  ;;
+        --keep_alive)   keep_alive="$2" ; shift ;;
+        --force_keepalive)   force_keepalive="$2" ; shift ;;
+        --disable_port_floating)    disable_port_floating="$2" ; shift  ;;
+        --virtual_private)  virtual_private="$2" ; shift ;; 
 	--strictcrlpolicy)	strictcrlpolicy="$2" ; shift	;;
 	--crlcheckinterval)	crlcheckinterval="$2"; shift	;;
 	--dump)	dumpdir="$2" ; shift	;;
@@ -84,6 +89,24 @@
 no|'')                                ;;
 *)    echo "unknown strictcrlpolicy value (not yes/no) \`$IPSECstrictcrlpolicy'"      ;;
 esac
+case "$nat_traversal" in
+yes)  popts="$popts --nat_traversal"  ;;
+no|'')                ;;
+*)    echo "unknown nat_traversal value (not yes/no) \`$IPSECnat_traversal'" ;;
+esac
+[ -n "$keep_alive" ] && popts="$popts --keep_alive $keep_alive"
+case "$force_keepalive" in
+yes)  popts="$popts --force_keepalive"  ;;
+no|'')                ;;
+*)    echo "unknown force_keepalive value (not yes/no) \`$IPSECforce_keepalive'" ;;
+esac
+case "$disable_port_floating" in
+yes)  popts="$popts --disable_port_floating"  ;;
+no|'')                ;;
+*)    echo "unknown disable_port_floating (not yes/no) \`$disable_port_floating'" ;;
+esac
+[ -n "$virtual_private" ] && popts="$popts --virtual_private $virtual_private"
+
 
 # add crl check interval
 if test ${crlcheckinterval:-0} -gt 0
diff -uNr freeswan-2.02.stock/programs/_realsetup/_realsetup.in freeswan-2.02/programs/_realsetup/_realsetup.in
--- freeswan-2.02.stock/programs/_realsetup/_realsetup.in	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/_realsetup/_realsetup.in	2003-10-10 22:45:56.000000000 -0400
@@ -217,6 +217,11 @@
 			--uniqueids "\"$IPSECuniqueids\"" \
 			--nocrsend "\"$IPSECnocrsend\"" \
 			--strictcrlpolicy "\"$IPSECstrictcrlpolicy\"" \
+			--nat_traversal "\"$IPSECnat_traversal\"" \
+			--keep_alive "\"$IPSECkeep_alive\"" \
+			--force_keepalive "\"$IPSECforce_keepalive\"" \
+			--disable_port_floating "\"$IPSECdisable_port_floating\"" \
+			--virtual_private "\"$IPSECvirtual_private\"" \
 			--crlcheckinterval "\"$IPSECcrlcheckinterval\"" \
 			--dump "\"$IPSECdumpdir\"" \
 			--opts "\"$IPSECplutoopts\"" \
diff -uNr freeswan-2.02.stock/programs/pluto/Makefile freeswan-2.02/programs/pluto/Makefile
--- freeswan-2.02.stock/programs/pluto/Makefile	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/Makefile	2003-10-11 09:52:10.000000000 -0400
@@ -107,6 +107,7 @@
 	-DX509=$(X509_VERSION) \
 	-DDEBUG \
 	-DGCC_LINT \
+	-DNAT_TRAVERSAL -DVIRTUAL_IP \
 	# -DLEAK_DETECTIVE
 
 # This compile option activates dynamic LDAP CRL fetching in the source code
@@ -211,6 +212,7 @@
 	timer.c timer.h \
 	x509.c x509.h \
 	$(DISTGCRYPT) \
+	vendor.c nat_traversal.c virtual.c \
 	adns.c adns.h \
 	whack.c whack.h
 
@@ -225,6 +227,7 @@
 	log.o state.o plutomain.o server.o timer.o oid.o pem.o pgp.o pkcs.o x509.o \
 	certs.o id.o ipsec_doi.o kernel.o rcv_whack.o demux.o packet.o lex.o keys.o \
 	smartcard.o ac.o dnskey.o fetch.o rnd.o spdb.o sha1.o md5.o md2.o \
+        vendor.o nat_traversal.o virtual.o \
 	${IPSECPOLICY_OBJS}
 
 OBJSADNS = adns.o
@@ -365,6 +368,7 @@
 log.o: log.c
 md2.o: md2.c
 md5.o: md5.c
+nat_traversal.o: nat_traversal.c
 oid.o: oid.c
 packet.o: packet.c
 pem.o: pem.c
@@ -381,6 +385,8 @@
 spdb.o: spdb.c
 state.o: state.c
 timer.o: timer.c
+vendor.o: vendor.c
+virtual.o: virtual.c
 whack.o: whack.c
 x509.o: x509.c
 
@@ -432,6 +438,8 @@
 connections.o: adns.h
 connections.o: dnskey.h
 connections.o: whack.h
+connections.o: nat_traversal.h
+connections.o: virtual.h
 constants.o: constants.h
 constants.o: defs.h
 constants.o: log.h
@@ -472,6 +480,8 @@
 demux.o: timer.h
 demux.o: whack.h
 demux.o: server.h
+demux.o: nat_traversal.h
+demux.o: vendor.h
 dnskey.o: constants.h
 dnskey.o: adns.h
 dnskey.o: defs.h
@@ -563,6 +573,9 @@
 ipsec_doi.o: sha1.h
 ipsec_doi.o: md5.h
 ipsec_doi.o: crypto.h
+ipsec_doi.o: vendor.h
+ipsec_doi.o: nat_traversal.h
+ipsec_doi.o: virtual.h
 kernel.o: constants.h
 kernel.o: defs.h
 kernel.o: rnd.h
@@ -579,6 +592,8 @@
 kernel.o: server.h
 kernel.o: whack.h
 kernel.o: keys.h
+kernel.o: packet.h
+kernel.o: nat_traversal.h
 keys.o: constants.h
 keys.o: defs.h
 keys.o: id.h
@@ -596,6 +611,7 @@
 keys.o: whack.h
 keys.o: timer.h
 keys.o: pkcs.h
+keys.o: nat_traversal.h
 lex.o: constants.h
 lex.o: defs.h
 lex.o: log.h
@@ -618,6 +634,28 @@
 md2.o: md2.h
 md5.o: md5.h
 md5.o: endian.h
+nat_traversal.o: constants.h
+nat_traversal.o: defs.h
+nat_traversal.o: log.h
+nat_traversal.o: id.h
+nat_traversal.o: x509.h
+nat_traversal.o: pgp.h
+nat_traversal.o: certs.h
+nat_traversal.o: smartcard.h
+nat_traversal.o: connections.h
+nat_traversal.o: packet.h
+nat_traversal.o: demux.h
+nat_traversal.o: whack.h
+nat_traversal.o: state.h
+nat_traversal.o: server.h
+nat_traversal.o: timer.h
+nat_traversal.o: sha1.h
+nat_traversal.o: md5.h
+nat_traversal.o: crypto.h
+nat_traversal.o: vendor.h
+nat_traversal.o: cookie.h
+nat_traversal.o: kernel.h
+nat_traversal.o: nat_traversal.h
 oid.o: oid.h
 packet.o: constants.h
 packet.o: defs.h
@@ -675,6 +713,8 @@
 plutomain.o: sha1.h
 plutomain.o: md5.h
 plutomain.o: crypto.h
+plutomain.o: virtual.h
+plutomain.o: nat_traversal.h
 primegen.o: constants.h
 primegen.o: defs.h
 primegen.o: log.h
@@ -729,6 +769,7 @@
 server.o: adns.h
 server.o: dnskey.h
 server.o: whack.h
+server.o: nat_traversal.h
 sha1.o: sha1.h
 sha1.o: endian.h
 smallprime.o: constants.h
@@ -761,6 +802,7 @@
 spdb.o: sha1.h
 spdb.o: md5.h
 spdb.o: crypto.h
+spdb.o: nat_traversal.h
 state.o: constants.h
 state.o: defs.h
 state.o: id.h
@@ -800,6 +842,31 @@
 timer.o: rnd.h
 timer.o: timer.h
 timer.o: whack.h
+timer.o: nat_traversal.h
+vendor.o: constants.h
+vendor.o: defs.h
+vendor.o: log.h
+vendor.o: md5.h
+vendor.o: id.h
+vendor.o: x509.h
+vendor.o: pgp.h
+vendor.o: certs.h
+vendor.o: connections.h
+vendor.o: packet.h
+vendor.o: demux.h
+vendor.o: whack.h
+vendor.o: vendor.h
+vendor.o: nat_traversal.h
+virtual.o: constants.h
+virtual.o: defs.h
+virtual.o: log.h
+virtual.o: id.h
+virtual.o: x509.h
+virtual.o: pgp.h
+virtual.o: certs.h
+virtual.o: connections.h
+virtual.o: whack.h
+virtual.o: virtual.h
 whack.o: constants.h
 whack.o: defs.h
 whack.o: whack.h
@@ -818,4 +885,3 @@
 x509.o: sha1.h
 x509.o: whack.h
 x509.o: fetch.h
-
diff -uNr freeswan-2.02.stock/programs/pluto/connections.c freeswan-2.02/programs/pluto/connections.c
--- freeswan-2.02.stock/programs/pluto/connections.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/connections.c	2003-10-11 09:38:50.000000000 -0400
@@ -52,6 +52,14 @@
 #include "dnskey.h"	/* needs keys.h and adns.h */
 #include "whack.h"
 
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+#ifdef VIRTUAL_IP
+#include "virtual.h"
+#endif
+
 static void flush_pending_by_connection(struct connection *c);	/* forward */
 
 static struct connection *connections = NULL;
@@ -100,6 +108,17 @@
     if (hisaddr == NULL)
 	hisaddr = aftoinfo(addrtypeof(myaddr))->any;
 
+#ifdef NAT_TRAVERSAL
+    if (nat_traversal_enabled) {
+	/**
+	 * port is not relevant in host_pair. with nat_traversal we
+	 * always use pluto_port (500)
+	 */
+	myport = pluto_port;
+	hisport = pluto_port;
+    }
+#endif
+
     for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next)
     {
 	if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport
@@ -124,6 +143,17 @@
 {
     struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport);
 
+#ifdef NAT_TRAVERSAL
+    if (nat_traversal_enabled && hp && hisaddr) {
+	struct connection *c;
+	for (c = hp->connections; c != NULL; c = c->hp_next) {
+	    if ((c->spd.this.host_port==myport) && (c->spd.that.host_port==hisport))
+		return c;
+	}
+	return NULL;
+    }
+#endif
+
     return hp == NULL? NULL : hp->connections;
 }
 
@@ -140,9 +170,14 @@
 	    /* no suitable host_pair -- build one */
 	    hp = alloc_thing(struct host_pair, "host_pair");
 	    hp->me.addr = c->spd.this.host_addr;
-	    hp->me.port = c->spd.this.host_port;
 	    hp->him.addr = c->spd.that.host_addr;
-	    hp->him.port = c->spd.that.host_port;
+#ifdef NAT_TRAVERSAL
+            hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port;
+            hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;
+#else
+            hp->me.port = c->spd.this.host_port;
+            hp->him.port = c->spd.that.host_port;
+#endif
 	    hp->initial_connection_sent = FALSE;
 	    hp->connections = NULL;
 	    hp->pending = NULL;
@@ -286,6 +321,10 @@
 	}
     }
 
+#ifdef VIRTUAL_IP
+    if (c->kind != CK_GOING_AWAY) pfreeany(c->spd.that.virt);
+#endif
+
 #ifdef DEBUG
     cur_debugging = old_cur_debugging;
 #endif
@@ -513,6 +552,12 @@
 
     client[0] = '\0';
 
+#ifdef VIRTUAL_IP
+    if (is_virtual_end(this) && isanyaddr(&this->host_addr)) {
+	host = "%virtual";
+    }
+#endif
+
     /* [client===] */
     if (this->has_client)
     {
@@ -848,6 +893,13 @@
 	    }
 	}
     }
+#ifdef VIRTUAL_IP
+    if ((this->virt) && (!isanyaddr(&this->host_addr) || this->has_client)) {
+	loglog(RC_CLASH,
+	    "virtual IP must only be used with %%any and without client");
+	return FALSE;
+    }
+#endif
     return TRUE;	/* happy */
 }
 
@@ -950,6 +1002,17 @@
 
 	c->gw_info = NULL;
 
+#ifdef VIRTUAL_IP
+	passert(!(wm->left.virt && wm->right.virt));
+	if (wm->left.virt || wm->right.virt) {
+	    passert(isanyaddr(&c->spd.that.host_addr));
+	    c->spd.that.virt = create_virtual(c,
+		wm->left.virt ? wm->left.virt : wm->right.virt);
+	    if (c->spd.that.virt)
+		c->spd.that.has_client = TRUE;
+	}
+#endif
+
 	unshare_connection_strings(c);
 
 	(void)orient(c);
@@ -1025,6 +1088,13 @@
 	t->kind = isanyaddr(&t->spd.that.host_addr) && !NEVER_NEGOTIATE(t->policy)
 	    ? CK_TEMPLATE : CK_INSTANCE;
 
+#ifdef VIRTUAL_IP
+	if (t->spd.that.virt) {
+		DBG_log("virtual_ip not supported in group instance");
+		t->spd.that.virt = NULL;
+	}
+#endif
+
 	/* add to connections list */
 	t->ac_next = connections;
 	connections = t;
@@ -1065,6 +1135,9 @@
  */
 static struct connection *
 instantiate(struct connection *c, const ip_address *him
+#ifdef NAT_TRAVERSAL
+, u_int16_t his_port
+#endif
 , const struct id *his_id)
 {
     struct connection *d;
@@ -1088,6 +1161,10 @@
 
     passert(oriented(*d));
     d->spd.that.host_addr = *him;
+#ifdef NAT_TRAVERSAL
+    if (his_port) d->spd.that.host_port = his_port;
+#endif
+
     default_end(&d->spd.that, &d->spd.this.host_addr);
 
     /* We cannot guess what our next_hop should be, but if it was
@@ -1113,9 +1190,28 @@
 struct connection *
 rw_instantiate(struct connection *c
 , const ip_address *him
+#ifdef NAT_TRAVERSAL
+, u_int16_t his_port
+#endif
+#ifdef VIRTUAL_IP
+, const ip_subnet *his_net
+#endif
 , const struct id *his_id)
 {
+#ifdef NAT_TRAVERSAL
+    struct connection *d = instantiate(c, him, his_port, his_id);
+#else
     struct connection *d = instantiate(c, him, his_id);
+#endif
+
+#ifdef VIRTUAL_IP
+    if (d && his_net && is_virtual_connection(c)) {
+	d->spd.that.client = *his_net;
+	d->spd.that.virt = NULL;
+	if (subnetishost(his_net) && addrinsubnet(him, his_net))
+	    d->spd.that.has_client = FALSE;
+    }
+#endif
 
     if (d->policy & POLICY_OPPO)
     {
@@ -1138,7 +1234,11 @@
 , const ip_address *our_client USED_BY_DEBUG
 , const ip_address *peer_client)
 {
+#ifdef NAT_TRAVERSAL
+    struct connection *d = instantiate(c, him, 0, his_id);
+#else
     struct connection *d = instantiate(c, him, his_id);
+#endif
 
     passert(d->spd.next == NULL);
 
@@ -1270,6 +1370,12 @@
 	{
 	    *p++ = ' ';
 	    addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF);
+#ifdef NAT_TRAVERSAL
+          if (c->spd.that.host_port != pluto_port) {
+              p += strlen(p);
+              sprintf(p, ":%d", c->spd.that.host_port);
+          }
+#endif 
 	}
     }
 }
@@ -1511,6 +1617,10 @@
 	     */
 	    for (p = interfaces; p != NULL; p = p->next)
 	    {
+#ifdef NAT_TRAVERSAL
+            if (p->ike_float) continue;
+#endif
+
 		for (;;)
 		{
 		    /* check if this interface matches this end */
@@ -2776,9 +2886,16 @@
 	{
 	    struct connection *next = d->ac_next;	/* might move underneath us */
 
+#ifdef NAT_TRAVERSAL
+            if (d->kind >= CK_PERMANENT
+            && same_id(&c->spd.that.id, &d->spd.that.id)
+            && (!sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr) ||
+            (c->spd.that.host_port != d->spd.that.host_port)))
+#else
 	    if (d->kind >= CK_PERMANENT
 	    && same_id(&c->spd.that.id, &d->spd.that.id)
 	    && !sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr))
+#endif
 	    {
 		release_connection(d);
 	    }
@@ -3084,6 +3201,12 @@
 	    if (d->policy & POLICY_GROUP)
 		continue;
 
+#ifdef NAT_TRAVERSAL
+	    if ((c->spd.that.host_port != d->spd.that.host_port) &&
+		(d->kind == CK_INSTANCE))
+		continue;
+#endif
+
 	    /* check if peer_id matches, exactly or after instantiation */
 	    if (!match)
 		continue;
@@ -3168,6 +3291,44 @@
     }
 }
 
+#ifdef VIRTUAL_IP
+/**
+ * With virtual addressing, we must not allow someone to use an already
+ * used (by another id) addr/net.
+ */
+static bool
+is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id)
+{
+    struct connection *d;
+    for (d = connections; d != NULL; d = d->ac_next)
+    {
+	switch (d->kind) {
+	    case CK_PERMANENT:
+	    case CK_TEMPLATE:
+	    case CK_INSTANCE:
+		if ((subnetinsubnet(peer_net,&d->spd.that.client) ||
+		     subnetinsubnet(&d->spd.that.client,peer_net)) &&
+		     !same_id(&d->spd.that.id, peer_id)) {
+		    char buf[IDTOA_BUF];
+		    char client[SUBNETTOT_BUF];
+		    subnettot(peer_net, 0, client, sizeof(client));
+		    idtoa(&d->spd.that.id, buf, sizeof(buf));
+		    plog("Virtual IP %s is already used by '%s'",
+			client, buf);
+		    idtoa(peer_id, buf, sizeof(buf));
+			plog("Your ID is '%s'", buf);
+		    return TRUE; /* already used by another one */
+		}
+		break;
+	    case CK_GOING_AWAY:
+	    default:
+		break;
+	}
+    }
+    return FALSE; /* you can safely use it */
+}
+#endif
+
 /* find_client_connection: given a connection suitable for ISAKMP
  * (i.e. the hosts match), find a one suitable for IPSEC
  * (i.e. with matching clients).
@@ -3201,6 +3362,7 @@
 static struct connection *
 fc_try(const struct connection *c
 , struct host_pair *hp
+, const struct id *peer_id
 , const ip_subnet *our_net
 , const ip_subnet *peer_net
 , const u_int8_t our_protocol
@@ -3276,8 +3438,20 @@
 		    if (!subnetinsubnet(peer_net, &sr->that.client))
 			continue;
 		} else {
+
+
+#ifdef VIRTUAL_IP
+                    if ((!samesubnet(&sr->that.client, peer_net)) && (!is_virtual_connection(sr)))
+#else
 		    if (!samesubnet(&sr->that.client, peer_net))
+#endif
 			continue;
+#ifdef VIRTUAL_IP
+                    if ((is_virtual_connection(sr)) &&
+                        ( (!is_virtual_net_allowed(sr, peer_net, &c->spd.that.host_addr)) ||
+                        (is_virtual_net_used(peer_net, peer_id?peer_id:&c->spd.that.id)) ))
+                            continue;
+#endif
 		}
 	    }
 	    else
@@ -3478,7 +3652,7 @@
 	}
 
 	/* exact match? */
-	d = fc_try(c, c->host_pair, our_net, peer_net
+	d = fc_try(c, c->host_pair,NULL, our_net, peer_net
 	    , our_protocol, our_port, peer_protocol, peer_port);
 
 	DBG(DBG_CONTROLMORE,
@@ -3520,7 +3694,7 @@
 	if (hp != NULL)
 	{
 	    /* RW match with actual peer_id or abstract peer_id? */
-	    d = fc_try(c, hp, our_net, peer_net
+	    d = fc_try(c, hp, NULL, our_net, peer_net
 		, our_protocol, our_port, peer_protocol, peer_port);
 
 	    if (d == NULL
@@ -3816,9 +3990,16 @@
 {
     struct pending *p;
 
-    for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next)
+    for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next) {
 	if (p->isakmp_sa == os)
 	    p->isakmp_sa = ns;
+#ifdef NAT_TRAVERSAL
+	if (p->connection->spd.this.host_port != ns->st_connection->spd.this.host_port) {
+	    p->connection->spd.this.host_port = ns->st_connection->spd.this.host_port;
+	    p->connection->spd.that.host_port = ns->st_connection->spd.that.host_port;
+	}
+#endif
+    }
 }
 
 /* a Main Mode negotiation has failed; discard any pending */
diff -uNr freeswan-2.02.stock/programs/pluto/connections.h freeswan-2.02/programs/pluto/connections.h
--- freeswan-2.02.stock/programs/pluto/connections.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/connections.h	2003-10-10 22:57:40.000000000 -0400
@@ -115,6 +115,12 @@
 #define POLICY_PRIO_BUF	(3+1+3+1)
 extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]);
 
+#ifdef VIRTUAL_IP
+	struct virtual_t;
+#endif
+
+
+
 struct end {
     struct id id;
     ip_address
@@ -132,6 +138,9 @@
     u_int8_t protocol;
     cert_t cert;		/* end certificate */
     chunk_t ca;			/* CA distinguished name */
+#ifdef VIRTUAL_IP
+    struct virtual_t *virt;
+#endif
     smartcard_t *sc;		/* smartcard reader and key info */
 };
 
@@ -259,6 +268,13 @@
 struct gw_info;	/* forward declaration of tag (defined in dnskey.h) */
 extern struct connection *rw_instantiate(struct connection *c
 					 , const ip_address *him
+#ifdef NAT_TRAVERSAL
+					 , u_int16_t his_port
+#endif
+#ifdef VIRTUAL_IP
+					 , const ip_subnet *his_net
+#endif
+
 					 , const struct id *his_id);
 
 extern struct connection *oppo_instantiate(struct connection *c
@@ -315,3 +331,10 @@
 extern void show_connections_status(void);
 extern int  connection_compare(const struct connection *ca
 			       , const struct connection *cb);
+
+#ifdef NAT_TRAVERSAL
+void update_host_pair(const char *why, struct connection *c,
+	const ip_address *myaddr, u_int16_t myport ,
+	const ip_address *hisaddr, u_int16_t hisport);
+#endif /* NAT_TRAVERSAL */
+
diff -uNr freeswan-2.02.stock/programs/pluto/constants.c freeswan-2.02/programs/pluto/constants.c
--- freeswan-2.02.stock/programs/pluto/constants.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/constants.c	2003-10-10 23:11:40.000000000 -0400
@@ -85,10 +85,17 @@
 	"EVENT_SA_REPLACE",
 	"EVENT_SA_REPLACE_IF_USED",
 	"EVENT_SA_EXPIRE",
+#ifdef NAT_TRAVERSAL
+	"EVENT_NAT_T_KEEPALIVE",
+#endif
     };
 
 enum_names timer_event_names =
+#ifdef NAT_TRAVERSAL
+    { EVENT_NULL, EVENT_NAT_T_KEEPALIVE, timer_event_name, NULL };
+#else
     { EVENT_NULL, EVENT_SA_EXPIRE, timer_event_name, NULL };
+#endif
 
 /* Domain of Interpretation */
 
@@ -222,11 +229,25 @@
 	"ISAKMP_NEXT_N",
 	"ISAKMP_NEXT_D",
 	"ISAKMP_NEXT_VID",
+#ifdef NAT_TRAVERSAL
+	"ISAKMP_NEXT_14",
+	"ISAKMP_NEXT_NAT-D",
+	"ISAKMP_NEXT_NAT-OA",
+#endif
 	NULL
     };
 
+#ifdef NAT_TRAVERSAL
+const char *const payload_name_nat_d[] = { "ISAKMP_NEXT_NAT-D",
+	"ISAKMP_NEXT_NAT-OA", NULL };
+static enum_names payload_names_nat_d =
+	{ ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL };
+enum_names payload_names =
+    { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d };
+#else
 enum_names payload_names =
     { ISAKMP_NEXT_NONE, ISAKMP_NEXT_VID, payload_name, NULL };
+#endif
 
 
 /* Exchange types (note: two discontinuous ranges) */
@@ -544,10 +565,28 @@
 static const char *const enc_mode_name[] = {
 	"ENCAPSULATION_MODE_TUNNEL",
 	"ENCAPSULATION_MODE_TRANSPORT",
+#ifdef NAT_TRAVERSAL
+	"ENCAPSULATION_MODE_UDP_TUNNEL",
+	"ENCAPSULATION_MODE_UDP_TRANSPORT",
+#endif
     };
 
+#ifdef NAT_TRAVERSAL
+static const char *const enc_udp_mode_name[] = {
+	"ENCAPSULATION_MODE_UDP_TUNNEL",
+	"ENCAPSULATION_MODE_UDP_TRANSPORT",
+    };
+#endif
+
+#ifdef NAT_TRAVERSAL
+static enum_names enc_udp_mode_names =
+    { ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS, ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS, enc_udp_mode_name, NULL };
+enum_names enc_mode_names =
+    { ENCAPSULATION_MODE_TUNNEL, ENCAPSULATION_MODE_UDP_TRANSPORT_RFC, enc_mode_name, &enc_udp_mode_names };
+#else
 enum_names enc_mode_names =
     { ENCAPSULATION_MODE_TUNNEL, ENCAPSULATION_MODE_TRANSPORT, enc_mode_name, NULL };
+#endif
 
 /* Auth Algorithm attribute */
 
diff -uNr freeswan-2.02.stock/programs/pluto/constants.h freeswan-2.02/programs/pluto/constants.h
--- freeswan-2.02.stock/programs/pluto/constants.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/constants.h	2003-10-10 23:20:12.000000000 -0400
@@ -181,6 +181,9 @@
     EVENT_SA_REPLACE_IF_USED,	/* SA replacement event */
     EVENT_SA_EXPIRE,	/* SA expiration event */
     EVENT_LOG_DAILY     /* reset certain log events/stats */
+#ifdef NAT_TRAVERSAL
+  , EVENT_NAT_T_KEEPALIVE
+#endif
 };
 
 #define EVENT_REINIT_SECRET_DELAY		3600 /* 1 hour */
@@ -244,12 +247,12 @@
 #define DBG_LIFECYCLE	LELEM(5)	/* SA lifecycle */
 #define DBG_KLIPS	LELEM(6)	/* messages to KLIPS */
 #define DBG_DNS		LELEM(7)	/* DNS activity */
-#define DBG_OPPO	LELEM(8)	/* opportunism */
-#define DBG_CONTROLMORE LELEM(9)	/* more detailed debugging */
-
-#define DBG_PRIVATE	LELEM(10)	/* private information: DANGER! */
+#define DBG_NATT      	LELEM(8)        /* NAT-T */
+#define DBG_OPPO      	LELEM(9)        /* opportunism */
+#define DBG_PRIVATE   	LELEM(10)       /* private information: DANGER! */
+#define DBG_CONTROLMORE LELEM(11)	/* more detailed debugging */
 
-#define IMPAIR0	11	/* first bit for IMPAIR_* */
+#define IMPAIR0	12	/* first bit for IMPAIR_* */
 
 #define IMPAIR_DELAY_ADNS_KEY_ANSWER	LELEM(IMPAIR0+0)	/* sleep before answering */
 #define IMPAIR_DELAY_ADNS_TXT_ANSWER	LELEM(IMPAIR0+1)	/* sleep before answering */
@@ -397,7 +400,15 @@
 #define ISAKMP_NEXT_D          12	/* Delete */
 #define ISAKMP_NEXT_VID        13	/* Vendor ID */
 
+#ifdef NAT_TRAVERSAL
+#define ISAKMP_NEXT_NATD_RFC   15   /* NAT-Traversal: NAT-D (rfc) */
+#define ISAKMP_NEXT_NATOA_RFC  16   /* NAT-Traversal: NAT-OA (rfc) */
+#define ISAKMP_NEXT_ROOF       17	/* roof on payload types */
+#define ISAKMP_NEXT_NATD_DRAFTS   130  /* NAT-Traversal: NAT-D (drafts) */
+#define ISAKMP_NEXT_NATOA_DRAFTS  131  /* NAT-Traversal: NAT-OA (drafts) */
+#else
 #define ISAKMP_NEXT_ROOF       14	/* roof on payload types */
+#endif
 
 /* Exchange types
  * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)"
@@ -638,6 +649,13 @@
 #define ENCAPSULATION_MODE_TUNNEL      1
 #define ENCAPSULATION_MODE_TRANSPORT   2
 
+#ifdef NAT_TRAVERSAL
+#define ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS       61443
+#define ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS    61444
+#define ENCAPSULATION_MODE_UDP_TUNNEL_RFC          3
+#define ENCAPSULATION_MODE_UDP_TRANSPORT_RFC       4
+#endif
+
 /* Auth Algorithm attribute */
 
 extern enum_names auth_alg_names, extended_auth_alg_names;
diff -uNr freeswan-2.02.stock/programs/pluto/demux.c freeswan-2.02/programs/pluto/demux.c
--- freeswan-2.02.stock/programs/pluto/demux.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/demux.c	2003-10-11 09:41:31.000000000 -0400
@@ -145,6 +145,11 @@
 #include "whack.h"	/* requires connections.h */
 #include "server.h"
 
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+#include "vendor.h"
+
 /* This file does basic header checking and demux of
  * incoming packets.
  */
@@ -270,7 +275,11 @@
      */
     { STATE_MAIN_R1, STATE_MAIN_R2
     , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+    , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(KE)
+#else
     , P(KE) | P(NONCE), P(VID) | P(CR), PT(KE)
+#endif
     , EVENT_RETRANSMIT, main_inI2_outR2 },
 
     { STATE_MAIN_R1, STATE_UNDEFINED
@@ -295,7 +304,11 @@
      */
     { STATE_MAIN_I2, STATE_MAIN_I3
     , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+    , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(ID)
+#else
     , P(KE) | P(NONCE), P(VID) | P(CR), PT(ID)
+#endif
     , EVENT_RETRANSMIT, main_inR2_outI3 },
 
     { STATE_MAIN_I2, STATE_UNDEFINED
@@ -386,7 +399,11 @@
      */
     { STATE_QUICK_R0, STATE_QUICK_R1
     , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+    , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(NONE)
+#else
     , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID), PT(NONE)
+#endif
     , EVENT_RETRANSMIT, quick_inI1_outR1 },
 
     /* STATE_QUICK_I1:
@@ -397,7 +414,11 @@
      */
     { STATE_QUICK_I1, STATE_QUICK_I2
     , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY
+#ifdef NAT_TRAVERSAL
+    , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(HASH)
+#else
     , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID), PT(HASH)
+#endif
     , EVENT_SA_REPLACE, quick_inR1_outI2 },
 
     /* STATE_QUICK_R1: HDR*, HASH(3) --> done
@@ -696,6 +717,19 @@
 		    /* note dirty trick to suppress ~ at start of format
 		     * if we know what state to blame.
 		     */
+
+#ifdef NAT_TRAVERSAL  
+                    if ((packet_len == 1) && (buffer[0] = 0xff)
+#ifdef DEBUG
+                        && ((cur_debugging & DBG_NATT) == 0)
+#endif
+                        ) {
+                        /* don't log NAT-T keepalive related errors unless NATT debug is
+                         * enabled
+                         */
+                    }
+                    else
+#endif
 		    plog((sender != NULL) + "~"
 			"ERROR: asynchronous network error report on %s"
 			"%s"
@@ -733,12 +767,40 @@
 #endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
 
 bool
+#ifdef NAT_TRAVERSAL
+_send_packet(struct state *st, const char *where, bool verbose)
+#else
 send_packet(struct state *st, const char *where)
+#endif
 {
     struct connection *c = st->st_connection;
     int port_buf;
     bool err;
 
+#ifdef NAT_TRAVERSAL
+    u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE];
+    u_int8_t *ptr;
+    unsigned long len;
+
+    if ((c->interface->ike_float == TRUE) && (st->st_tpacket.len != 1)) {
+	if ((unsigned long) st->st_tpacket.len >
+	    (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t))) {
+	    DBG_log("send_packet(): really too big");
+	    return FALSE;
+	}
+	ptr = ike_pkt;
+	/** Add Non-ESP marker **/
+	memset(ike_pkt, 0, sizeof(u_int32_t));
+	memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr,
+	    (unsigned long)st->st_tpacket.len);
+	len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t);
+    }
+    else {
+	ptr = st->st_tpacket.ptr;
+	len = (unsigned long) st->st_tpacket.len;
+    }
+#endif
+
     DBG(DBG_RAW,
 	{
 	    DBG_log("sending %lu bytes for %s through %s to %s:%u:"
@@ -762,16 +824,29 @@
     (void) check_msg_errqueue(c->interface, POLLOUT);
 #endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */
 
+#ifdef NAT_TRAVERSAL
+     err = sendto(c->interface->fd
+         , ptr, len, 0 
+         , sockaddrof(&c->spd.that.host_addr)
+         , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)len;
+#else
     err = sendto(c->interface->fd
     , st->st_tpacket.ptr, st->st_tpacket.len, 0
     , sockaddrof(&c->spd.that.host_addr)
     , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)st->st_tpacket.len;
+#endif
     
     /* restore port */
     setportof(port_buf, &c->spd.that.host_addr);
 
     if (err)
     {
+#ifdef NAT_TRAVERSAL
+        /* do not log NAT-T Keep Alive packets */
+        if (!verbose)
+            return FALSE;
+#endif
+
 	log_errno((e, "sendto on %s to %s:%u failed in %s"
 	    , c->interface->rname
 	    , ip_str(&c->spd.that.host_addr)
@@ -916,6 +991,9 @@
     int packet_len;
     /* ??? this buffer seems *way* too big */
     u_int8_t bigbuffer[MAX_INPUT_UDP_SIZE];
+#ifdef NAT_TRAVERSAL
+    u_int8_t *_buffer = bigbuffer;
+#endif
     union
     {
 	struct sockaddr sa;
@@ -1011,11 +1089,34 @@
     cur_from = &md->sender;
     cur_from_port = md->sender_port;
 
+#ifdef NAT_TRAVERSAL
+    if (ifp->ike_float == TRUE) {
+	u_int32_t non_esp;
+	if (packet_len < (int)sizeof(u_int32_t)) {
+	    plog("recvfrom %s:%u too small packet (%d)"
+		, ip_str(cur_from), (unsigned) cur_from_port, packet_len);
+	    return FALSE;
+	}
+	memcpy(&non_esp, _buffer, sizeof(u_int32_t));
+	if (non_esp != 0) {
+	    plog("recvfrom %s:%u has no Non-ESP marker"
+		, ip_str(cur_from), (unsigned) cur_from_port);
+	    return FALSE;
+	}
+	_buffer += sizeof(u_int32_t);
+	packet_len -= sizeof(u_int32_t);
+    }
+#endif
+
     /* Clone actual message contents
      * and set up md->packet_pbs to describe it.
      */
     init_pbs(&md->packet_pbs
+#ifdef NAT_TRAVERSAL
+	, clone_bytes(_buffer, packet_len, "message buffer in comm_handle()")
+#else
 	, clone_bytes(bigbuffer, packet_len, "message buffer in comm_handle()")
+#endif
 	, packet_len, "packet");
 
     DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL,
@@ -1030,6 +1131,22 @@
     DBG(DBG_RAW,
 	DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs)));
 
+#ifdef NAT_TRAVERSAL
+	if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff)) {
+		/**
+		 * NAT-T Keep-alive packets should be discared by kernel ESPinUDP
+		 * layer. But boggus keep-alive packets (sent with a non-esp marker)
+		 * can reach this point. Complain and discard them.
+		 */
+		DBG(DBG_NATT,
+			DBG_log("NAT-T keep-alive (boggus ?) should not reach this point. "
+				"Ignored. Sender: %s:%u", ip_str(cur_from),
+				(unsigned) cur_from_port);
+			);
+		return FALSE;
+	}
+#endif
+
     return TRUE;
 }
 
@@ -1480,6 +1597,22 @@
 		return;
 	    }
 
+#ifdef NAT_TRAVERSAL
+	    switch (np)
+	    {
+		case ISAKMP_NEXT_NATD_RFC:
+		case ISAKMP_NEXT_NATOA_RFC:
+		    if ((!st) || (!(st->nat_traversal & NAT_T_WITH_RFC_VALUES))) {
+			/*
+			 * don't accept NAT-D/NAT-OA reloc directly in message, unless
+			 * we're using NAT-T RFC
+			 */
+			sd = NULL;
+		    }
+		    break;
+	    }
+#endif
+
 	    if (sd == NULL)
 	    {
 		/* payload type is out of range or requires special handling */
@@ -1489,6 +1622,16 @@
 		    sd = IS_PHASE1(from_state)
 			? &isakmp_identification_desc : &isakmp_ipsec_identification_desc;
 		    break;
+#ifdef NAT_TRAVERSAL
+		case ISAKMP_NEXT_NATD_DRAFTS:
+		    np = ISAKMP_NEXT_NATD_RFC;  /* NAT-D relocated */
+		    sd = payload_descs[np];
+		    break;
+		case ISAKMP_NEXT_NATOA_DRAFTS:
+		    np = ISAKMP_NEXT_NATOA_RFC;  /* NAT-OA relocated */
+		    sd = payload_descs[np];
+		    break;
+#endif
 		default:
 		    loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or"
 			" unexpected payload type (%s) at the outermost level"
@@ -1660,6 +1803,7 @@
 
 	for (p = md->chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next)
 	{
+#if 0
 	    char vid_string[48];
 	    size_t vid_len = sizeof(vid_string) - 1 < pbs_left(&p->pbs)
 		? sizeof(vid_string) - 1 : pbs_left(&p->pbs);
@@ -1673,6 +1817,8 @@
 	    loglog(RC_LOG, "received Vendor ID Payload; ASCII hash: %s"
 		, vid_string);
 	    DBG_cond_dump(DBG_PARSING, "VID:", p->pbs.cur, pbs_left(&p->pbs));
+#endif
+		handle_vendorid(md, p->pbs.cur, pbs_left(&p->pbs));
 	}
     }
     md->from_state = from_state;
@@ -1746,6 +1892,12 @@
 		clonetochunk(st->st_tpacket, md->reply.start
 		    , pbs_offset(&md->reply), "reply packet");
 
+#ifdef NAT_TRAVERSAL
+		if (nat_traversal_enabled) {
+		    nat_traversal_change_port_lookup(md, md->st);
+		}
+#endif
+
 		/* actually send the packet
 		 * Note: this is a great place to implement "impairments"
 		 * for testing purposes.  Suppress or duplicate the
diff -uNr freeswan-2.02.stock/programs/pluto/demux.h freeswan-2.02/programs/pluto/demux.h
--- freeswan-2.02.stock/programs/pluto/demux.h	2003-03-13 21:35:19.000000000 -0500
+++ freeswan-2.02/programs/pluto/demux.h	2003-10-10 23:11:40.000000000 -0400
@@ -16,7 +16,12 @@
 
 struct state;	/* forward declaration of tag */
 extern void init_demux(void);
+#ifdef NAT_TRAVERSAL
+#define send_packet(st,wh) _send_packet(st,wh,TRUE)
+extern bool _send_packet(struct state *st, const char *where, bool verbose);
+#else
 extern bool send_packet(struct state *st, const char *where);
+#endif
 extern void comm_handle(const struct iface *ifp);
 
 extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE];
@@ -65,6 +70,9 @@
 	digest[PAYLIMIT],
 	*digest_roof,
 	*chain[ISAKMP_NEXT_ROOF];
+#ifdef NAT_TRAVERSAL
+	unsigned short nat_traversal_vid;
+#endif
 };
 
 extern void release_md(struct msg_digest *md);
diff -uNr freeswan-2.02.stock/programs/pluto/ipsec_doi.c freeswan-2.02/programs/pluto/ipsec_doi.c
--- freeswan-2.02.stock/programs/pluto/ipsec_doi.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/ipsec_doi.c	2003-10-11 09:40:20.000000000 -0400
@@ -58,6 +58,15 @@
 #include "md5.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
 
+#include "vendor.h"
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+#ifdef VIRTUAL_IP
+#include "virtual.h"
+#endif
+
 static bool encrypt_message(pb_stream *pbs, struct state *st);	/* forward declaration */
 
 /* OpenPGP Vendor ID needed for interoperability with PGPnet
@@ -652,6 +661,11 @@
 	    }
 	    else
 	    {
+#ifdef NAT_TRAVERSAL
+		if (nat_traversal_enabled) {
+		    nat_traversal_change_port_lookup(md, dst);
+		}
+#endif
 		loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
 		    "deleting ISAKMP State #%lu", dst->st_serialno);
 		delete_state(dst);
@@ -679,6 +693,11 @@
 	    {
 		struct connection *rc = dst->st_connection;
 
+#ifdef NAT_TRAVERSAL
+		if (nat_traversal_enabled) {
+		    nat_traversal_change_port_lookup(md, dst);
+		}
+#endif
 		if (rc->newest_ipsec_sa == dst->st_serialno
 		&& (rc->policy & POLICY_UP))
 		    {
@@ -826,6 +845,16 @@
 	    return STF_INTERNAL_ERROR;
     }
 
+#ifdef NAT_TRAVERSAL
+    if (nat_traversal_enabled) {
+	/* Add supported NAT-Traversal VID */
+	if (!nat_traversal_add_vid(ISAKMP_NEXT_NONE, &rbody)) {
+	    reset_cur_state();
+	    return STF_INTERNAL_ERROR;
+	}
+    }
+#endif
+
     close_message(&rbody);
     close_output_pbs(&reply);
 
@@ -1922,6 +1951,22 @@
 	plog("initiating Quick Mode %s to replace #%lu"
 	    , prettypolicy(policy), replacing);
 
+#ifdef NAT_TRAVERSAL
+      if (isakmp_sa->nat_traversal & NAT_T_DETECTED) {
+        /* Duplicate nat_traversal status in new state */
+        st->nat_traversal = isakmp_sa->nat_traversal;
+        if (isakmp_sa->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) {
+            has_client = TRUE;
+        }
+        nat_traversal_change_port_lookup(NULL, st);
+      }
+      else {   
+        st->nat_traversal = 0;
+      }
+#endif
+
+
+
     /* set up reply */
     init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet");
 
@@ -2007,6 +2052,18 @@
 	}
     }
 
+#ifdef NAT_TRAVERSAL
+    if ((st->nat_traversal & NAT_T_WITH_NATOA) &&
+	(!(st->st_policy & POLICY_TUNNEL)) &&
+	(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))) {
+	/** Send NAT-OA if our address is NATed */
+	if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) {
+        reset_cur_state();
+	    return STF_INTERNAL_ERROR;
+	}
+    }
+#endif
+
     /* finish computing  HASH(1), inserting it in output */
     (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur
 	, st, &st->st_msgid, FALSE);
@@ -2170,6 +2227,16 @@
      * Besides, there is no good reason for allowing these to be
      * other than 0 in Phase 1.
      */
+#ifdef NAT_TRAVERSAL
+    if ((st->nat_traversal & NAT_T_WITH_PORT_FLOATING) &&
+	(id->isaid_doi_specific_a == IPPROTO_UDP) &&
+	((id->isaid_doi_specific_b == 0) || (id->isaid_doi_specific_b == NAT_T_IKE_FLOAT_PORT))) {
+	    DBG_log("protocol/port in Phase 1 ID Payload is %d/%d. "
+		"accepted with port_floating NAT-T",
+		id->isaid_doi_specific_a, id->isaid_doi_specific_b);
+    }
+    else
+#endif
     if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0)
     && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT))
     {
@@ -2312,8 +2379,15 @@
 	    if (r->kind == CK_TEMPLATE)
 	    {
 		/* instantiate it, filling in peer's ID */
-		r = rw_instantiate(r, &c->spd.that.host_addr, &peer);
-	    }
+                r = rw_instantiate(r, &c->spd.that.host_addr,
+#ifdef NAT_TRAVERSAL
+                      c->spd.that.host_port,
+#endif
+#ifdef VIRTUAL_IP
+                      NULL,
+#endif
+                      &peer);
+            }
 
 	    st->st_connection = r;	/* kill reference to c */
 	    set_cur_connection(r);
@@ -2790,7 +2864,7 @@
 	{
 	    loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u"
 		" but no connection has been authorized"
-		, ip_str(&md->iface->addr), pluto_port);
+		, ip_str(&md->iface->addr), ntohs(portof(&md->iface->addr)));
 	    /* XXX notification is in order! */
 	    return STF_IGNORE;
 	}
@@ -2807,7 +2881,14 @@
 	    /* Create a temporary connection that is a copy of this one.
 	     * His ID isn't declared yet.
 	     */
-	    c = rw_instantiate(c, &md->sender, NULL);
+	    c = rw_instantiate(c, &md->sender,
+#ifdef NAT_TRAVERSAL
+			md->sender_port,
+#endif
+#ifdef VIRTUAL_IP
+			NULL,
+#endif
+			NULL);
 	}
     }
 
@@ -2826,7 +2907,13 @@
     st->st_doi = ISAKMP_DOI_IPSEC;
     st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */
 
-    if (c->kind == CK_INSTANCE)
+if ((c->kind == CK_INSTANCE) && (c->spd.that.host_port != pluto_port))
+      {
+        plog("responding to Main Mode from unknown peer %s:%u"
+            , ip_str(&c->spd.that.host_addr), c->spd.that.host_port);
+      }
+      else if (c->kind == CK_INSTANCE)
+
     {
 	plog("responding to Main Mode from unknown peer %s"
 	    , ip_str(&c->spd.that.host_addr));
@@ -2880,6 +2967,17 @@
 	    return STF_INTERNAL_ERROR;
     }
 
+#ifdef NAT_TRAVERSAL
+    if (md->nat_traversal_vid && nat_traversal_enabled) {
+	/* reply if NAT-Traversal draft is supported */
+	st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid);
+	if ((st->nat_traversal) && (!out_vendorid(ISAKMP_NEXT_NONE,
+	    &md->rbody, md->nat_traversal_vid))) {
+	    return STF_INTERNAL_ERROR;
+	}
+    }
+#endif
+
     close_message(&md->rbody);
 
     /* save initiator SA for HASH */
@@ -2911,6 +3009,12 @@
 	    , &sapd->payload.sa, NULL, TRUE, st));
     }
 
+#ifdef NAT_TRAVERSAL
+    if (nat_traversal_enabled && md->nat_traversal_vid) {
+	st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid);
+    }
+#endif
+
     /**************** build output packet HDR;KE;Ni ****************/
 
     /* HDR out.
@@ -2948,6 +3052,14 @@
     if (!build_and_ship_nonce(&st->st_ni, &md->rbody, ISAKMP_NEXT_NONE, "Ni"))
 	return STF_INTERNAL_ERROR;
 #endif
+
+#ifdef NAT_TRAVERSAL
+    if (st->nat_traversal & NAT_T_WITH_NATD) {
+	if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
+	    return STF_INTERNAL_ERROR;
+    }
+#endif
+
     /* finish message */
     close_message(&md->rbody);
 
@@ -2985,6 +3097,19 @@
     /* Ni in */
     RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
 
+#ifdef NAT_TRAVERSAL
+     if (st->nat_traversal & NAT_T_WITH_NATD) {
+        nat_traversal_natd_lookup(md);
+      }
+      if (st->nat_traversal) {
+        nat_traversal_show_result(st->nat_traversal, md->sender_port);
+      }
+      if (st->nat_traversal & NAT_T_WITH_KA) {
+        nat_traversal_new_ka_event();
+      }  
+#endif
+
+
     /* decode certificate requests */
     decode_cr(md, &st->st_connection->requested_ca);
 
@@ -3059,6 +3184,14 @@
 	}
     }
 
+#ifdef NAT_TRAVERSAL
+      if (st->nat_traversal & NAT_T_WITH_NATD) {
+        if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
+            return STF_INTERNAL_ERROR;
+      }
+#endif
+
+
     /* finish message */
     close_message(&md->rbody);
 
@@ -3121,6 +3254,18 @@
     if (!generate_skeyids_iv(st))
 	return STF_FAIL + AUTHENTICATION_FAILED;
 
+#ifdef NAT_TRAVERSAL
+	if (st->nat_traversal & NAT_T_WITH_NATD) {
+	    nat_traversal_natd_lookup(md);
+	}
+	if (st->nat_traversal) {
+	    nat_traversal_show_result(st->nat_traversal, md->sender_port);
+	}
+	if (st->nat_traversal & NAT_T_WITH_KA) {
+	    nat_traversal_new_ka_event();
+	}
+#endif
+
     /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/
     /* ??? NOTE: this is almost the same as main_inI3_outR3's code */
 
@@ -4288,7 +4433,16 @@
 		    /* Plain Road Warrior:
 		     * instantiate, carrying over authenticated peer ID
 		     */
-		    p = rw_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id);
+
+                    p = rw_instantiate(p, &c->spd.that.host_addr,
+#ifdef NAT_TRAVERSAL
+                                md->sender_port,
+#endif
+#ifdef VIRTUAL_IP
+                                his_net,
+#endif 
+                                &c->spd.that.id);
+
 		}
 	    }
 #ifdef DEBUG
@@ -4311,6 +4465,16 @@
 	    p->spd.that.client = *his_net;
 	    p->spd.that.has_client_wildcard = FALSE;
 	}
+#ifdef VIRTUAL_IP
+       else if (is_virtual_connection(c))
+       {
+           c->spd.that.client = *his_net;
+           c->spd.that.virt = NULL;
+           if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net))
+               c->spd.that.has_client = FALSE;
+       }
+#endif
+
     }
 
     /* now that we are sure of our connection, create our new state */
@@ -4357,6 +4521,19 @@
 	st->st_policy = (p1st->st_policy & POLICY_ISAKMP_MASK)
 	    | (c->policy & ~POLICY_ISAKMP_MASK);
 
+#ifdef NAT_TRAVERSAL
+	if (p1st->nat_traversal & NAT_T_DETECTED) {
+	    st->nat_traversal = p1st->nat_traversal;
+	    nat_traversal_change_port_lookup(md, md->st);
+	}
+	else {
+	    st->nat_traversal = 0;
+	}
+	if ((st->nat_traversal & NAT_T_DETECTED) &&
+	    (st->nat_traversal & NAT_T_WITH_NATOA)) {
+	    nat_traversal_natoa_lookup(md);
+	}
+#endif
 
 	/* Start the output packet.
 	 *
@@ -4444,6 +4621,24 @@
 	    p->isaiid_np = ISAKMP_NEXT_NONE;
 	}
 
+#ifdef NAT_TRAVERSAL
+	if ((st->nat_traversal & NAT_T_WITH_NATOA) &&
+	    (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) &&
+	    (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT)) {
+	    /** Send NAT-OA if our address is NATed and if we use Transport Mode */
+	    if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &md->rbody, md->st)) {
+		return STF_INTERNAL_ERROR;
+	    }
+	}
+	if ((st->nat_traversal & NAT_T_DETECTED) &&
+	    (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) &&
+	    (c->spd.that.has_client)) {
+	    /** Remove client **/
+	    addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client);
+	    c->spd.that.has_client = FALSE;
+	}
+#endif
+
 	/* Compute reply HASH(2) and insert in output */
 	(void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur
 	    , st, &st->st_msgid, TRUE);
@@ -4541,6 +4736,13 @@
 	}
     }
 
+#ifdef NAT_TRAVERSAL
+	if ((st->nat_traversal & NAT_T_DETECTED) &&
+	    (st->nat_traversal & NAT_T_WITH_NATOA)) {
+	    nat_traversal_natoa_lookup(md);
+	}
+#endif
+
     /* ??? We used to copy the accepted proposal into the state, but it was
      * never used.  From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs).
      */
diff -uNr freeswan-2.02.stock/programs/pluto/kernel.c freeswan-2.02/programs/pluto/kernel.c
--- freeswan-2.02.stock/programs/pluto/kernel.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/kernel.c	2003-10-11 09:41:05.000000000 -0400
@@ -56,6 +56,11 @@
 #include "whack.h"	/* for RC_LOG_SERIOUS */
 #include "keys.h"
 
+#ifdef NAT_TRAVERSAL
+#include "packet.h"  /* for pb_stream in nat_traversal.h */
+#include "nat_traversal.h"
+#endif
+
 bool can_do_IPcomp = TRUE;  /* can system actually perform IPCOMP? */
 
 /* How far can IPsec messages arrive out of order before the anti-replay
@@ -206,6 +211,9 @@
 	NE(SADB_X_ADDFLOW),
 	NE(SADB_X_DELFLOW),
 	NE(SADB_X_DEBUG),
+#ifdef NAT_TRAVERSAL
+	NE(SADB_X_NAT_T_NEW_MAPPING),
+#endif
 	NE(SADB_MAX),
 	{ 0, sparse_end }
 };
@@ -374,7 +382,11 @@
 		, (unsigned) IPSEC_PFKEYv2_ALIGN);
 	}
 	else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
-	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)))
+	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
+#ifdef NAT_TRAVERSAL
+	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)
+#endif
+	))
 	{
 	    /* not for us: ignore */
 	    DBG(DBG_KLIPS,
@@ -617,6 +629,11 @@
 	    /* to simulate loss of ACQUIRE, delete this call */
 	    process_pfkey_acquire(buf, extensions);
 	    break;
+#ifdef NAT_TRAVERSAL
+	case SADB_X_NAT_T_NEW_MAPPING:
+	    process_pfkey_nat_t_new_mapping(&(buf->msg), extensions);
+	    break;
+#endif
 	default:
 	    /* ignored */
 	    break;
@@ -1032,6 +1049,9 @@
 
     /* if routing would affect IKE messages, reject */
     if (!no_klips
+#ifdef NAT_TRAVERSAL
+    && c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT
+#endif
     && c->spd.this.host_port != IKE_UDP_PORT
     && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client))
     {
@@ -2360,6 +2380,20 @@
 		SADB_EALG_3DESCBC, SADB_AALG_SHA1HMAC },
 	};
 
+#ifdef NAT_TRAVERSAL
+	u_int8_t natt_type = 0;
+	u_int16_t natt_sport = 0, natt_dport = 0;
+	ip_address natt_oa;
+
+	if (st->nat_traversal & NAT_T_DETECTED) {
+	    natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ?
+		ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE;
+	    natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port;
+	    natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
+	    natt_oa = st->nat_oa;
+	}
+#endif
+
 	for (ei = esp_info; ; ei++)
 	{
 	    if (ei == &esp_info[elemsof(esp_info)])
@@ -2412,6 +2446,26 @@
 		    , esp_dst_keymat)
 		, "pfkey_key_a Add ESP SA", text_said, extensions))
 
+#ifdef NAT_TRAVERSAL
+	&& (natt_type == 0
+		|| pfkey_build(pfkey_x_nat_t_type_build(
+			&extensions[SADB_X_EXT_NAT_T_TYPE], natt_type),
+			"pfkey_nat_t_type Add ESP SA", text_said, extensions))
+	&& (natt_sport == 0
+		|| pfkey_build(pfkey_x_nat_t_port_build(
+			&extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT,
+			natt_sport), "pfkey_nat_t_sport Add ESP SA", text_said,
+			extensions))
+	&& (natt_dport == 0
+		|| pfkey_build(pfkey_x_nat_t_port_build(
+			&extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT,
+			natt_dport), "pfkey_nat_t_dport Add ESP SA", text_said,
+			extensions))
+	&& (natt_type ==0 || isanyaddr(&natt_oa)
+		|| pfkeyext_address(SADB_X_EXT_NAT_T_OA, &natt_oa
+	    , "pfkey_nat_t_oa Add ESP SA", text_said, extensions))
+#endif
+
 	&& finish_pfkey_msg(extensions, "Add ESP SA", text_said, NULL)))
 
 	    goto fail;
@@ -3100,6 +3154,87 @@
 #endif /* !KLIPS */
 }
 
+#ifdef NAT_TRAVERSAL
+#ifdef KLIPS
+static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound)
+{
+      struct connection *c = st->st_connection;
+      ip_address
+              src = inbound? c->spd.that.host_addr : c->spd.this.host_addr,
+              dst = inbound? c->spd.this.host_addr : c->spd.that.host_addr;
+ 
+      struct sadb_ext *extensions[SADB_EXT_MAX + 1];
+      char text_said[SATOT_BUF];
+
+      ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;
+ 
+       u_int16_t
+              natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port,
+              natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port;
+              
+      set_text_said(text_said, &dst, esp_spi, SA_ESP);
+      
+      return (!(pfkey_msg_start(SADB_UPDATE, SADB_SATYPE_ESP
+              , "pfkey_msg_hdr Update ESP SA", text_said, extensions)
+      
+      && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
+              , SADB_EXT_SA
+              , esp_spi   /* in network order */
+              , 0, SADB_SASTATE_MATURE, st->st_esp.attrs.auth /* dummy, not used */,
+                      st->st_esp.attrs.transid /* dummy, not used */, 0)
+              , "pfkey_sa Update ESP SA", text_said, extensions)
+      
+      && pfkeyext_address(SADB_EXT_ADDRESS_SRC, &src
+              , "pfkey_addr_s Update ESP SA", text_said, extensions) 
+      
+      && pfkeyext_address(SADB_EXT_ADDRESS_DST, &dst
+              , "pfkey_addr_d Update ESP SA", text_said, extensions)
+              
+      && pfkey_build(pfkey_x_nat_t_port_build(
+              &extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT,
+              natt_sport), "pfkey_nat_t_sport Update ESP SA", text_said,
+              extensions)
+      
+      && pfkey_build(pfkey_x_nat_t_port_build(
+              &extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT,
+              natt_dport), "pfkey_nat_t_dport Update ESP SA", text_said,
+              extensions)
+              
+      && finish_pfkey_msg(extensions, "Update ESP SA", text_said, NULL)))
+              
+      ? FALSE : TRUE;
+}
+#endif
+
+bool update_ipsec_sa (struct state *st USED_BY_KLIPS)
+{
+#ifdef KLIPS
+      if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) {
+              if ((st->st_esp.present) && (
+                      (!update_nat_t_ipsec_esp_sa (st, TRUE)) ||
+                      (!update_nat_t_ipsec_esp_sa (st, FALSE)))) {
+                      return FALSE;
+              }
+      }
+      else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) {
+              if ((st->st_esp.present) && (!update_nat_t_ipsec_esp_sa (st, FALSE))) {
+                      return FALSE;
+              }
+      }
+      else {
+              DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__,
+                      st->st_state);
+              return FALSE;
+      }
+      return TRUE;
+#else /* !KLIPS */
+    DBG(DBG_CONTROL, DBG_log("if I knew how, I'd update_ipsec_sa()"));
+    return TRUE;
+#endif /* !KLIPS */
+}
+#endif
+   
+
 
 /*
  * Local Variables:
diff -uNr freeswan-2.02.stock/programs/pluto/kernel.h freeswan-2.02/programs/pluto/kernel.h
--- freeswan-2.02.stock/programs/pluto/kernel.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/kernel.h	2003-10-10 23:23:26.000000000 -0400
@@ -69,3 +69,7 @@
 extern bool route_and_eroute(struct connection *c
 			     , struct spd_route *sr
 			     , struct state *st);
+#ifdef NAT_TRAVERSAL
+extern bool update_ipsec_sa(struct state *st);
+#endif
+
diff -uNr freeswan-2.02.stock/programs/pluto/keys.c freeswan-2.02/programs/pluto/keys.c
--- freeswan-2.02.stock/programs/pluto/keys.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/keys.c	2003-10-11 09:41:49.000000000 -0400
@@ -57,6 +57,12 @@
 /* Maximum length of filename and passphrase buffer */
 #define BUF_LEN		256
 
+#ifdef NAT_TRAVERSAL 
+#define PB_STREAM_UNDEFINED
+#include "nat_traversal.h"
+#endif
+
+
 struct fld {
     const char *name;
     size_t offset;
@@ -335,6 +341,18 @@
 	happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
 	his_id = &rw_id;
     }
+#ifdef NAT_TRAVERSAL
+    else if ((nat_traversal_enabled) && (c->policy & POLICY_PSK) &&
+       (kind == PPK_PSK) && (
+           ((c->kind == CK_TEMPLATE) && (c->spd.that.id.kind == ID_NONE)) ||
+           ((c->kind == CK_INSTANCE) && (id_is_ipaddr(&c->spd.that.id)))))
+     {
+       /* roadwarrior: replace him with 0.0.0.0 */
+       rw_id.kind = ID_IPV4_ADDR;
+       happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
+       his_id = &rw_id;
+     }
+#endif
 
     for (s = secrets; s != NULL; s = s->next)
     {
diff -uNr freeswan-2.02.stock/programs/pluto/nat_traversal.c freeswan-2.02/programs/pluto/nat_traversal.c
--- freeswan-2.02.stock/programs/pluto/nat_traversal.c	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/nat_traversal.c	2003-10-11 09:55:06.000000000 -0400
@@ -0,0 +1,827 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: nat_traversal.c,v 1.16 2003/01/13 17:57:15 mathieu Exp $
+ */
+
+#ifdef NAT_TRAVERSAL
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <freeswan.h>
+#include <freeswan/ipsec_policy.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "whack.h"
+#include "state.h"
+#include "server.h"
+#include "timer.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "vendor.h"
+#include "cookie.h"
+#include "kernel.h"
+
+#include "nat_traversal.h"
+
+/* #define FORCE_NAT_TRAVERSAL */
+#define NAT_D_DEBUG
+#define NAT_T_SUPPORT_LAST_DRAFTS
+
+#ifndef SOL_UDP
+#define SOL_UDP 17
+#endif
+
+#ifndef UDP_ESPINUDP
+#define UDP_ESPINUDP    100
+#endif
+
+#define DEFAULT_KEEP_ALIVE_PERIOD  20
+
+#ifdef _IKE_ALG_H
+/* Alg patch: hash_digest_len -> hash_digest_size */
+#define hash_digest_len hash_digest_size
+#endif
+
+bool nat_traversal_enabled = FALSE;
+bool nat_traversal_support_port_floating = FALSE;
+
+static unsigned int _kap = 0;
+static unsigned int _ka_evt = 0;
+static bool _force_ka = 0;
+
+static const char *natt_version = "0.6";
+
+static const char *natt_methods[] = {
+	"draft-ietf-ipsec-nat-t-ike-00/01",
+	"draft-ietf-ipsec-nat-t-ike-02/03",
+	"RFC XXXX (NAT-Traversal)"
+};
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+	bool fka, bool spf)
+{
+	nat_traversal_enabled = activate;
+#ifdef NAT_T_SUPPORT_LAST_DRAFTS
+	nat_traversal_support_port_floating = activate ? spf : FALSE;
+#endif
+	_force_ka = fka;
+	_kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD;
+	plog("  including NAT-Traversal patch (Version %s)%s%s%s",
+		natt_version, activate ? "" : " [disabled]",
+		activate & fka ? " [Force KeepAlive]" : "",
+		activate & !spf ? " [Port Floating disabled]" : "");
+}
+
+static void disable_nat_traversal (void)
+{
+	nat_traversal_enabled = FALSE; 
+	nat_traversal_support_port_floating = FALSE;
+}
+
+static void _natd_hash(const struct hash_desc *hasher, char *hash,
+	u_int8_t *icookie, u_int8_t *rcookie,
+	const ip_address *ip, u_int16_t port)
+{
+	union hash_ctx ctx;
+
+	if (is_zero_cookie(icookie))
+		DBG_log("_natd_hash: Warning, icookie is zero !!");
+	if (is_zero_cookie(rcookie))
+		DBG_log("_natd_hash: Warning, rcookie is zero !!");
+
+	/**
+	 * draft-ietf-ipsec-nat-t-ike-01.txt
+	 *
+	 *   HASH = HASH(CKY-I | CKY-R | IP | Port)
+	 *
+	 * All values in network order
+	 */
+	hasher->hash_init(&ctx);
+	hasher->hash_update(&ctx, icookie, COOKIE_SIZE);
+	hasher->hash_update(&ctx, rcookie, COOKIE_SIZE);
+	switch (addrtypeof(ip)) {
+		case AF_INET:
+			hasher->hash_update(&ctx,
+				(const u_char *)&ip->u.v4.sin_addr.s_addr,
+				sizeof(ip->u.v4.sin_addr.s_addr));
+			break;
+		case AF_INET6:
+			hasher->hash_update(&ctx,
+				(const u_char *)&ip->u.v6.sin6_addr.s6_addr,
+				sizeof(ip->u.v6.sin6_addr.s6_addr));
+			break;
+	}
+	hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t));
+	hasher->hash_final(hash, &ctx);
+#ifdef NAT_D_DEBUG
+	DBG(DBG_NATT,
+		DBG_log("_natd_hash: hasher=%p(%d)", hasher, hasher->hash_digest_len);
+		DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE);
+		DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE);
+		switch (addrtypeof(ip)) {
+			case AF_INET:
+				DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr,
+					sizeof(ip->u.v4.sin_addr.s_addr));
+				break;
+		}
+		DBG_log("_natd_hash: port=%d", port);
+		DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len);
+	);
+#endif
+}
+
+/**
+ * Add NAT-Traversal VIDs (supported ones)
+ *
+ * Used when we're Initiator
+ */
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs)
+{
+	bool r = TRUE;
+	if (nat_traversal_support_port_floating) {
+#if 0
+		if (r) r = out_vendorid(np, outs, VID_NATT_RFC);
+#endif
+		if (r) r = out_vendorid(np, outs, VID_NATT_IETF_03);
+		if (r) r = out_vendorid(np, outs, VID_NATT_IETF_02);
+	}
+	if (r) r = out_vendorid(np, outs, VID_NATT_IETF_00);
+	return r;
+}
+
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid)
+{
+	switch (nat_t_vid) {
+		case VID_NATT_IETF_00:
+			return LELEM(NAT_TRAVERSAL_IETF_00_01);
+			break;
+		case VID_NATT_IETF_02:
+		case VID_NATT_IETF_02_N:
+		case VID_NATT_IETF_03:
+			return LELEM(NAT_TRAVERSAL_IETF_02_03);
+			break;
+		case VID_NATT_RFC:
+			return LELEM(NAT_TRAVERSAL_RFC);
+			break;
+	}
+	return 0;
+}
+
+void nat_traversal_natd_lookup(struct msg_digest *md)
+{
+	char hash[MAX_DIGEST_LEN];
+	struct payload_digest *p;
+	struct state *st = md->st;
+	int i;
+
+	if (!st || !md->iface || !st->st_oakley.hasher) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return;
+	}
+
+	/** Count NAT-D **/
+	for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++);
+
+	/**
+	 * We need at least 2 NAT-D (1 for us, many for peer)
+	 */
+	if (i < 2) {
+		loglog(RC_LOG_SERIOUS,
+		"NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negociation", i);
+		st->nat_traversal = 0;
+		return;
+	}
+
+	/**
+	 * First one with my IP & port
+	 */
+	p = md->chain[ISAKMP_NEXT_NATD_RFC];
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+		&(md->iface->addr), ntohs(st->st_connection->spd.this.host_port));
+	if (!( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) &&
+		(memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0)
+		)) {
+#ifdef NAT_D_DEBUG
+		DBG(DBG_NATT,
+			DBG_log("NAT_TRAVERSAL_NAT_BHND_ME");
+			DBG_dump("expected NAT-D:", hash,
+				st->st_oakley.hasher->hash_digest_len);
+			DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+		);
+#endif
+		st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+	}
+
+	/**
+	 * The others with sender IP & port
+	 */
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+		&(md->sender), ntohs(md->sender_port));
+	for (p = p->next, i=0 ; p != NULL; p = p->next) {
+		if ( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) &&
+			(memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0)
+			) {
+			i++;
+		}
+	}
+	if (!i) {
+#ifdef NAT_D_DEBUG
+		DBG(DBG_NATT,
+			DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER");
+			DBG_dump("expected NAT-D:", hash,
+				st->st_oakley.hasher->hash_digest_len);
+			p = md->chain[ISAKMP_NEXT_NATD_RFC];
+			for (p = p->next, i=0 ; p != NULL; p = p->next) {
+				DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+			}
+		);
+#endif
+		st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+	}
+#ifdef FORCE_NAT_TRAVERSAL
+	st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+	st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+#endif
+}
+
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+	struct msg_digest *md)
+{
+	char hash[MAX_DIGEST_LEN];
+	struct state *st = md->st;
+
+	if (!st || !st->st_oakley.hasher) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return FALSE;
+	}
+
+	if (!out_modify_previous_np((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+		? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), outs)) {
+		return FALSE;
+	}
+
+	/**
+	 * First one with sender IP & port
+	 */
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+		is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+		&(md->sender),
+#ifdef FORCE_NAT_TRAVERSAL
+		0
+#else
+		ntohs(md->sender_port)
+#endif
+	);
+	if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+		? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs,
+		hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")) {
+		return FALSE;
+	}
+
+	/**
+	 * Second one with my IP & port
+	 */
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+		is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+		&(md->iface->addr),
+#ifdef FORCE_NAT_TRAVERSAL
+		0
+#else
+		ntohs(st->st_connection->spd.this.host_port)
+#endif
+	);
+	return (out_generic_raw(np, &isakmp_nat_d, outs,
+		hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));
+}
+
+/**
+ * nat_traversal_natoa_lookup()
+ * 
+ * Look for NAT-OA in message
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md)
+{
+	struct payload_digest *p;
+	struct state *st = md->st;
+	int i;
+	ip_address ip;
+
+	if (!st || !md->iface) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return;
+	}
+
+	/** Initialize NAT-OA */
+	anyaddr(AF_INET, &st->nat_oa);
+
+	/** Count NAT-OA **/
+	for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++);
+
+	DBG(DBG_NATT,
+		DBG_log("NAT-Traversal: received %d NAT-OA.", i);
+	);
+
+	if (i==0) {
+		return;
+	}
+	else if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+			"ignored because peer is not NATed", i);
+		return;
+	}
+	else if (i>1) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+			"using first, ignoring others", i);
+	}
+
+	/** Take first **/
+	p = md->chain[ISAKMP_NEXT_NATOA_RFC];
+
+	DBG(DBG_PARSING,
+		DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs));
+	);
+
+	switch (p->payload.nat_oa.isanoa_idtype) {
+		case ID_IPV4_ADDR:
+			if (pbs_left(&p->pbs) == sizeof(struct in_addr)) {
+				initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip);
+			}
+			else {
+				loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA "
+					"with invalid IP size (%d)", pbs_left(&p->pbs));
+				return;
+			}
+			break;
+		case ID_IPV6_ADDR:
+			if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) {
+				initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip);
+			}
+			else {
+				loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA "
+					"with invalid IP size (%d)", pbs_left(&p->pbs));
+				return;
+			}
+			break;
+		default:
+			loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+				"invalid ID Type (%d) in NAT-OA - ignored",
+				p->payload.nat_oa.isanoa_idtype);
+			return;
+			break;
+	}
+
+	DBG(DBG_NATT,
+		{
+			char ip_t[ADDRTOT_BUF];
+			addrtot(&ip, 0, ip_t, sizeof(ip_t));
+			DBG_log("received NAT-OA: %s", ip_t);
+		}
+	);
+
+	if (isanyaddr(&ip)) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA...");
+	}
+	else {
+		st->nat_oa = ip;
+	}
+}
+
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+	struct state *st)
+{
+	struct isakmp_nat_oa natoa;
+	pb_stream pbs;
+	unsigned char ip_val[sizeof(struct in6_addr)];
+	size_t ip_len = 0;
+	ip_address *ip;
+
+	if ((!st) || (!st->st_connection)) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return FALSE;
+	}
+	ip = &(st->st_connection->spd.this.host_addr);
+
+	if (!out_modify_previous_np((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+		? ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS), outs)) {
+		return FALSE;
+	}
+
+	memset(&natoa, 0, sizeof(natoa));
+	natoa.isanoa_np = np;
+
+	switch (addrtypeof(ip)) {
+		case AF_INET:
+			ip_len = sizeof(ip->u.v4.sin_addr.s_addr);
+			memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len);
+			natoa.isanoa_idtype = ID_IPV4_ADDR;
+			break;
+		case AF_INET6:
+			ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr);
+			memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len);
+			natoa.isanoa_idtype = ID_IPV6_ADDR;
+			break;
+		default:
+			loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+				"invalid addrtypeof()=%d", addrtypeof(ip));
+			return FALSE;
+	}
+
+	if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs))
+		return FALSE;
+
+	if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA"))
+		return FALSE;
+
+	DBG(DBG_NATT,
+		DBG_dump("NAT-OA (S):", ip_val, ip_len);
+	);
+
+	close_output_pbs(&pbs);
+	return TRUE;
+}
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport)
+{
+	const char *mth = NULL, *rslt = NULL;
+	switch (nt & NAT_TRAVERSAL_METHOD) {
+		case LELEM(NAT_TRAVERSAL_IETF_00_01):
+			mth = natt_methods[0];
+			break;
+		case LELEM(NAT_TRAVERSAL_IETF_02_03):
+			mth = natt_methods[1];
+			break;
+		case LELEM(NAT_TRAVERSAL_RFC):
+			mth = natt_methods[2];
+			break;
+	}
+	switch (nt & NAT_T_DETECTED) {
+		case 0:
+			rslt = "no NAT detected";
+			break;
+		case LELEM(NAT_TRAVERSAL_NAT_BHND_ME):
+			rslt = "i am NATed";
+			break;
+		case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+			rslt = "peer is NATed";
+			break;
+		case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+			rslt = "both are NATed";
+			break;
+	}
+	loglog(RC_LOG_SERIOUS,
+		"NAT-Traversal: Result using %s: %s",
+		mth ? mth : "unknown method",
+		rslt ? rslt : "unknown result"
+		);
+	if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)) &&
+		(sport == IKE_UDP_PORT) &&
+		((nt & NAT_T_WITH_PORT_FLOATING)==0)) {
+		loglog(RC_LOG_SERIOUS,
+			"Warning: peer is NATed but source port is still udp/%d. "
+			"Ipsec-passthrough NAT device suspected -- NAT-T may not work.",
+			IKE_UDP_PORT
+		);
+	}
+}
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type)
+{
+	int r;
+	r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type));
+	if ((r<0) && (errno == ENOPROTOOPT)) {
+		loglog(RC_LOG_SERIOUS,
+			"NAT-Traversal: ESPINUDP(%d) not supported by kernel -- "
+			"NAT-T disabled", type);
+		disable_nat_traversal();
+	}
+	return r;
+}
+
+void nat_traversal_new_ka_event (void)
+{
+	if (_ka_evt) return;  /* Event already schedule */
+	event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL);
+	_ka_evt = 1;
+}
+
+static void nat_traversal_send_ka (struct state *st)
+{
+	static unsigned char ka_payload = 0xff;
+	chunk_t sav;
+
+	DBG(DBG_NATT,
+		DBG_log("ka_event: send NAT-KA to %s:%d",
+			ip_str(&st->st_connection->spd.that.host_addr),
+			st->st_connection->spd.that.host_port);
+	);
+
+	/** save state chunk */
+	setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len);
+
+	/** send keep alive */
+	setchunk(st->st_tpacket, &ka_payload, 1);
+	_send_packet(st, "NAT-T Keep Alive", FALSE);
+
+	/** restore state chunk */
+	setchunk(st->st_tpacket, sav.ptr, sav.len);
+}
+
+/**
+ * Find ISAKMP States with NAT-T and send keep-alive
+ */
+static void nat_traversal_ka_event_state (struct state *st, void *data)
+{
+	unsigned int *_kap_st = (unsigned int *)data;
+	const struct connection *c = st->st_connection;
+	if (!c) return;
+	if ( ((st->st_state == STATE_MAIN_R3) ||
+			(st->st_state == STATE_MAIN_I4)) &&
+		(st->nat_traversal & NAT_T_DETECTED) &&
+		((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || (_force_ka))
+		) {
+		/**
+		 * - ISAKMP established
+		 * - NAT-Traversal detected
+		 * - NAT-KeepAlive needed (we are NATed)
+		 */
+		if (c->newest_isakmp_sa != st->st_serialno) {
+			/** 
+			 * if newest is also valid, ignore this one, we will only use
+			 * newest. 
+			 */
+			struct state *st_newest;
+			st_newest = state_with_serialno(c->newest_isakmp_sa);
+			if ((st_newest) && ((st_newest->st_state==STATE_MAIN_R3) ||
+				(st_newest->st_state==STATE_MAIN_I4)) &&
+				(st_newest->nat_traversal & NAT_T_DETECTED) &&
+				((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
+				|| (_force_ka))) {
+				return;
+			}
+		}
+		set_cur_state(st);
+		nat_traversal_send_ka(st);
+		reset_cur_state();
+		(*_kap_st)++;
+	}
+}
+
+void nat_traversal_ka_event (void)
+{
+	unsigned int _kap_st = 0;
+
+	_ka_evt = 0;  /* ready to be reschedule */
+
+	for_each_state((void *)nat_traversal_ka_event_state, &_kap_st);
+
+	if (_kap_st) {
+		/**
+		 * If there are still states who needs Keep-Alive, schedule new event
+		 */
+		nat_traversal_new_ka_event();
+	}
+}
+
+struct _new_mapp_nfo {
+	ip_address addr;
+	u_int16_t sport, dport;
+};
+
+static void nat_traversal_find_new_mapp_state (struct state *st, void *data)
+{
+	struct connection *c = st->st_connection;
+	struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data;
+
+	if ((c) && sameaddr(&c->spd.that.host_addr, &(nfo->addr)) &&
+		(c->spd.that.host_port == nfo->sport)) {
+
+		/**
+		 * Change host port
+		 */
+		c->spd.that.host_port = nfo->dport;
+
+		if (IS_IPSEC_SA_ESTABLISHED(st->st_state) ||
+			IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) {
+			if (!update_ipsec_sa(st)) {
+				/**
+				 * If ipsec update failed, restore old port or we'll
+				 * not be able to update anymore.
+				 */
+				c->spd.that.host_port = nfo->sport;
+			}
+		}
+	}
+}
+
+static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport,
+	const ip_address *dst, u_int16_t dport)
+{
+	char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF];
+	struct _new_mapp_nfo nfo;
+
+	addrtot(src, 0, srca, ADDRTOT_BUF);
+	addrtot(dst, 0, dsta, ADDRTOT_BUF);
+
+	if (!sameaddr(src, dst)) {
+		loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: "
+			"address change currently not supported [%s:%d,%s:%d]",
+			srca, sport, dsta, dport);
+		return -1;
+	}
+
+	if (sport == dport) {
+		/* no change */
+		return 0;
+	}
+
+	DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport);
+
+	nfo.addr = *src;
+	nfo.sport = sport;
+	nfo.dport = dport;
+
+	for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo);
+
+	return 0;
+}
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st)
+{
+	struct connection *c = st ? st->st_connection : NULL;
+	struct iface *i = NULL;
+
+	if ((st == NULL) || (c == NULL)) {
+		return;
+	}
+
+	if (md) {
+		/**
+		 * If source port has changed, update (including other states and
+		 * established kernel SA)
+		 */
+		if (c->spd.that.host_port != md->sender_port) {
+			nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
+				&c->spd.that.host_addr, md->sender_port);
+		}
+
+		/**
+		 * If interface type has changed, update local port (500/4500)
+		 */
+		if (((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT) &&
+			 (md->iface->ike_float == FALSE)) ||
+			((c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT) &&
+			 (md->iface->ike_float == TRUE))) {
+			c->spd.this.host_port = (md->iface->ike_float == TRUE)
+				? NAT_T_IKE_FLOAT_PORT : pluto_port;
+			DBG(DBG_NATT,
+				DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port);
+			);
+		}
+	}
+
+	/**
+	 * If we're initiator and NAT-T (with port floating) is detected, we
+	 * need to change port (MAIN_I3 or QUICK_I1)
+	 */
+	if (((st->st_state == STATE_MAIN_I3) || (st->st_state == STATE_QUICK_I1)) &&
+		(st->nat_traversal & NAT_T_WITH_PORT_FLOATING) &&
+		(st->nat_traversal & NAT_T_DETECTED) &&
+		(c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT)) {
+		DBG(DBG_NATT,
+			DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT);
+		);
+		c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT;
+		c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT;
+		/*
+		 * Also update pending connections or they will be deleted if uniqueids
+		 * option is set.
+		 */
+		update_pending(st, st);
+	}
+
+	/**
+	 * Find valid interface according to local port (500/4500)
+	 */
+	if (((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT) &&
+		 (c->interface->ike_float == FALSE)) ||
+		((c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT) &&
+		 (c->interface->ike_float == TRUE))) {
+		for (i = interfaces; i !=  NULL; i = i->next) {
+			if ((sameaddr(&c->interface->addr, &i->addr)) &&
+				(i->ike_float != c->interface->ike_float)) {
+				DBG(DBG_NATT,
+					DBG_log("NAT-T: using interface %s:%d", i->rname,
+						i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port);
+				);
+				c->interface = i;
+				break;
+			}
+		}
+	}
+}
+
+struct _new_klips_mapp_nfo {
+	struct sadb_sa *sa;
+	ip_address src, dst;
+	u_int16_t sport, dport;
+};
+
+static void nat_t_new_klips_mapp (struct state *st, void *data)
+{
+	struct connection *c = st->st_connection;
+	struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data;
+
+	if ((c) && (st->st_esp.present) &&
+		sameaddr(&c->spd.that.host_addr, &(nfo->src)) &&
+		(st->st_esp.our_spi == nfo->sa->sadb_sa_spi)) {
+		nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
+			&(nfo->dst), nfo->dport);
+	}
+}
+
+void process_pfkey_nat_t_new_mapping(
+	struct sadb_msg *msg __attribute__ ((unused)),
+	struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+	struct _new_klips_mapp_nfo nfo;
+	struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
+	struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
+	struct sockaddr *srca, *dsta;
+	err_t ugh = NULL;
+
+	nfo.sa = (void *) extensions[SADB_EXT_SA];
+
+	if ((!nfo.sa) || (!srcx) || (!dstx)) {
+		plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: "
+			"got NULL params");
+		return;
+	}
+
+	srca = ((struct sockaddr *)(void *)&srcx[1]);
+	dsta = ((struct sockaddr *)(void *)&dstx[1]);
+
+	if ((srca->sa_family != AF_INET) || (dsta->sa_family != AF_INET)) {
+		ugh = "only AF_INET supported";
+	}
+	else {
+		char text_said[SATOT_BUF];
+		char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF];
+		ip_said said;
+
+		initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr,
+			sizeof(((const struct sockaddr_in *)srca)->sin_addr),
+			srca->sa_family, &(nfo.src));
+		nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port);
+		initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr,
+			sizeof(((const struct sockaddr_in *)dsta)->sin_addr),
+			dsta->sa_family, &(nfo.dst));
+		nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port);
+
+		DBG(DBG_NATT,
+			initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said);
+			satot(&said, 0, text_said, SATOT_BUF);
+			addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF);
+			addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF);
+			DBG_log("new klips mapping %s %s:%d %s:%d",
+				text_said, _srca, nfo.sport, _dsta, nfo.dport);
+		);
+
+		for_each_state((void *)nat_t_new_klips_mapp, &nfo);
+	}
+
+	if (ugh != NULL)
+		plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh);
+}
+
+#endif
+
diff -uNr freeswan-2.02.stock/programs/pluto/nat_traversal.c.old freeswan-2.02/programs/pluto/nat_traversal.c.old
--- freeswan-2.02.stock/programs/pluto/nat_traversal.c.old	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/nat_traversal.c.old	2003-10-11 09:48:14.000000000 -0400
@@ -0,0 +1,826 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: nat_traversal.c,v 1.16 2003/01/13 17:57:15 mathieu Exp $
+ */
+
+#ifdef NAT_TRAVERSAL
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "whack.h"
+#include "state.h"
+#include "server.h"
+#include "timer.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "vendor.h"
+#include "cookie.h"
+#include "kernel.h"
+
+#include "nat_traversal.h"
+
+/* #define FORCE_NAT_TRAVERSAL */
+#define NAT_D_DEBUG
+#define NAT_T_SUPPORT_LAST_DRAFTS
+
+#ifndef SOL_UDP
+#define SOL_UDP 17
+#endif
+
+#ifndef UDP_ESPINUDP
+#define UDP_ESPINUDP    100
+#endif
+
+#define DEFAULT_KEEP_ALIVE_PERIOD  20
+
+#ifdef _IKE_ALG_H
+/* Alg patch: hash_digest_len -> hash_digest_size */
+#define hash_digest_len hash_digest_size
+#endif
+
+bool nat_traversal_enabled = FALSE;
+bool nat_traversal_support_port_floating = FALSE;
+
+static unsigned int _kap = 0;
+static unsigned int _ka_evt = 0;
+static bool _force_ka = 0;
+
+static const char *natt_version = "0.6";
+
+static const char *natt_methods[] = {
+	"draft-ietf-ipsec-nat-t-ike-00/01",
+	"draft-ietf-ipsec-nat-t-ike-02/03",
+	"RFC XXXX (NAT-Traversal)"
+};
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+	bool fka, bool spf)
+{
+	nat_traversal_enabled = activate;
+#ifdef NAT_T_SUPPORT_LAST_DRAFTS
+	nat_traversal_support_port_floating = activate ? spf : FALSE;
+#endif
+	_force_ka = fka;
+	_kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD;
+	plog("  including NAT-Traversal patch (Version %s)%s%s%s",
+		natt_version, activate ? "" : " [disabled]",
+		activate & fka ? " [Force KeepAlive]" : "",
+		activate & !spf ? " [Port Floating disabled]" : "");
+}
+
+static void disable_nat_traversal (void)
+{
+	nat_traversal_enabled = FALSE; 
+	nat_traversal_support_port_floating = FALSE;
+}
+
+static void _natd_hash(const struct hash_desc *hasher, char *hash,
+	u_int8_t *icookie, u_int8_t *rcookie,
+	const ip_address *ip, u_int16_t port)
+{
+	union hash_ctx ctx;
+
+	if (is_zero_cookie(icookie))
+		DBG_log("_natd_hash: Warning, icookie is zero !!");
+	if (is_zero_cookie(rcookie))
+		DBG_log("_natd_hash: Warning, rcookie is zero !!");
+
+	/**
+	 * draft-ietf-ipsec-nat-t-ike-01.txt
+	 *
+	 *   HASH = HASH(CKY-I | CKY-R | IP | Port)
+	 *
+	 * All values in network order
+	 */
+	hasher->hash_init(&ctx);
+	hasher->hash_update(&ctx, icookie, COOKIE_SIZE);
+	hasher->hash_update(&ctx, rcookie, COOKIE_SIZE);
+	switch (addrtypeof(ip)) {
+		case AF_INET:
+			hasher->hash_update(&ctx,
+				(const u_char *)&ip->u.v4.sin_addr.s_addr,
+				sizeof(ip->u.v4.sin_addr.s_addr));
+			break;
+		case AF_INET6:
+			hasher->hash_update(&ctx,
+				(const u_char *)&ip->u.v6.sin6_addr.s6_addr,
+				sizeof(ip->u.v6.sin6_addr.s6_addr));
+			break;
+	}
+	hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t));
+	hasher->hash_final(hash, &ctx);
+#ifdef NAT_D_DEBUG
+	DBG(DBG_NATT,
+		DBG_log("_natd_hash: hasher=%p(%d)", hasher, hasher->hash_digest_len);
+		DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE);
+		DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE);
+		switch (addrtypeof(ip)) {
+			case AF_INET:
+				DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr,
+					sizeof(ip->u.v4.sin_addr.s_addr));
+				break;
+		}
+		DBG_log("_natd_hash: port=%d", port);
+		DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len);
+	);
+#endif
+}
+
+/**
+ * Add NAT-Traversal VIDs (supported ones)
+ *
+ * Used when we're Initiator
+ */
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs)
+{
+	bool r = TRUE;
+	if (nat_traversal_support_port_floating) {
+#if 0
+		if (r) r = out_vendorid(np, outs, VID_NATT_RFC);
+#endif
+		if (r) r = out_vendorid(np, outs, VID_NATT_IETF_03);
+		if (r) r = out_vendorid(np, outs, VID_NATT_IETF_02);
+	}
+	if (r) r = out_vendorid(np, outs, VID_NATT_IETF_00);
+	return r;
+}
+
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid)
+{
+	switch (nat_t_vid) {
+		case VID_NATT_IETF_00:
+			return LELEM(NAT_TRAVERSAL_IETF_00_01);
+			break;
+		case VID_NATT_IETF_02:
+		case VID_NATT_IETF_02_N:
+		case VID_NATT_IETF_03:
+			return LELEM(NAT_TRAVERSAL_IETF_02_03);
+			break;
+		case VID_NATT_RFC:
+			return LELEM(NAT_TRAVERSAL_RFC);
+			break;
+	}
+	return 0;
+}
+
+void nat_traversal_natd_lookup(struct msg_digest *md)
+{
+	char hash[MAX_DIGEST_LEN];
+	struct payload_digest *p;
+	struct state *st = md->st;
+	int i;
+
+	if (!st || !md->iface || !st->st_oakley.hasher) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return;
+	}
+
+	/** Count NAT-D **/
+	for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++);
+
+	/**
+	 * We need at least 2 NAT-D (1 for us, many for peer)
+	 */
+	if (i < 2) {
+		loglog(RC_LOG_SERIOUS,
+		"NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negociation", i);
+		st->nat_traversal = 0;
+		return;
+	}
+
+	/**
+	 * First one with my IP & port
+	 */
+	p = md->chain[ISAKMP_NEXT_NATD_RFC];
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+		&(md->iface->addr), ntohs(st->st_connection->this.host_port));
+	if (!( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) &&
+		(memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0)
+		)) {
+#ifdef NAT_D_DEBUG
+		DBG(DBG_NATT,
+			DBG_log("NAT_TRAVERSAL_NAT_BHND_ME");
+			DBG_dump("expected NAT-D:", hash,
+				st->st_oakley.hasher->hash_digest_len);
+			DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+		);
+#endif
+		st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+	}
+
+	/**
+	 * The others with sender IP & port
+	 */
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
+		&(md->sender), ntohs(md->sender_port));
+	for (p = p->next, i=0 ; p != NULL; p = p->next) {
+		if ( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) &&
+			(memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0)
+			) {
+			i++;
+		}
+	}
+	if (!i) {
+#ifdef NAT_D_DEBUG
+		DBG(DBG_NATT,
+			DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER");
+			DBG_dump("expected NAT-D:", hash,
+				st->st_oakley.hasher->hash_digest_len);
+			p = md->chain[ISAKMP_NEXT_NATD_RFC];
+			for (p = p->next, i=0 ; p != NULL; p = p->next) {
+				DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
+			}
+		);
+#endif
+		st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+	}
+#ifdef FORCE_NAT_TRAVERSAL
+	st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
+	st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
+#endif
+}
+
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+	struct msg_digest *md)
+{
+	char hash[MAX_DIGEST_LEN];
+	struct state *st = md->st;
+
+	if (!st || !st->st_oakley.hasher) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return FALSE;
+	}
+
+	if (!out_modify_previous_np((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+		? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), outs)) {
+		return FALSE;
+	}
+
+	/**
+	 * First one with sender IP & port
+	 */
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+		is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+		&(md->sender),
+#ifdef FORCE_NAT_TRAVERSAL
+		0
+#else
+		ntohs(md->sender_port)
+#endif
+	);
+	if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+		? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs,
+		hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")) {
+		return FALSE;
+	}
+
+	/**
+	 * Second one with my IP & port
+	 */
+	_natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
+		is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
+		&(md->iface->addr),
+#ifdef FORCE_NAT_TRAVERSAL
+		0
+#else
+		ntohs(st->st_connection->this.host_port)
+#endif
+	);
+	return (out_generic_raw(np, &isakmp_nat_d, outs,
+		hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));
+}
+
+/**
+ * nat_traversal_natoa_lookup()
+ * 
+ * Look for NAT-OA in message
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md)
+{
+	struct payload_digest *p;
+	struct state *st = md->st;
+	int i;
+	ip_address ip;
+
+	if (!st || !md->iface) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return;
+	}
+
+	/** Initialize NAT-OA */
+	anyaddr(AF_INET, &st->nat_oa);
+
+	/** Count NAT-OA **/
+	for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++);
+
+	DBG(DBG_NATT,
+		DBG_log("NAT-Traversal: received %d NAT-OA.", i);
+	);
+
+	if (i==0) {
+		return;
+	}
+	else if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+			"ignored because peer is not NATed", i);
+		return;
+	}
+	else if (i>1) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
+			"using first, ignoring others", i);
+	}
+
+	/** Take first **/
+	p = md->chain[ISAKMP_NEXT_NATOA_RFC];
+
+	DBG(DBG_PARSING,
+		DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs));
+	);
+
+	switch (p->payload.nat_oa.isanoa_idtype) {
+		case ID_IPV4_ADDR:
+			if (pbs_left(&p->pbs) == sizeof(struct in_addr)) {
+				initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip);
+			}
+			else {
+				loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA "
+					"with invalid IP size (%d)", pbs_left(&p->pbs));
+				return;
+			}
+			break;
+		case ID_IPV6_ADDR:
+			if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) {
+				initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip);
+			}
+			else {
+				loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA "
+					"with invalid IP size (%d)", pbs_left(&p->pbs));
+				return;
+			}
+			break;
+		default:
+			loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+				"invalid ID Type (%d) in NAT-OA - ignored",
+				p->payload.nat_oa.isanoa_idtype);
+			return;
+			break;
+	}
+
+	DBG(DBG_NATT,
+		{
+			char ip_t[ADDRTOT_BUF];
+			addrtot(&ip, 0, ip_t, sizeof(ip_t));
+			DBG_log("received NAT-OA: %s", ip_t);
+		}
+	);
+
+	if (isanyaddr(&ip)) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA...");
+	}
+	else {
+		st->nat_oa = ip;
+	}
+}
+
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+	struct state *st)
+{
+	struct isakmp_nat_oa natoa;
+	pb_stream pbs;
+	unsigned char ip_val[sizeof(struct in6_addr)];
+	size_t ip_len = 0;
+	ip_address *ip;
+
+	if ((!st) || (!st->st_connection)) {
+		loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d",
+			__FILE__, __LINE__);
+		return FALSE;
+	}
+	ip = &(st->st_connection->this.host_addr);
+
+	if (!out_modify_previous_np((st->nat_traversal & NAT_T_WITH_RFC_VALUES
+		? ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS), outs)) {
+		return FALSE;
+	}
+
+	memset(&natoa, 0, sizeof(natoa));
+	natoa.isanoa_np = np;
+
+	switch (addrtypeof(ip)) {
+		case AF_INET:
+			ip_len = sizeof(ip->u.v4.sin_addr.s_addr);
+			memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len);
+			natoa.isanoa_idtype = ID_IPV4_ADDR;
+			break;
+		case AF_INET6:
+			ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr);
+			memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len);
+			natoa.isanoa_idtype = ID_IPV6_ADDR;
+			break;
+		default:
+			loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+				"invalid addrtypeof()=%d", addrtypeof(ip));
+			return FALSE;
+	}
+
+	if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs))
+		return FALSE;
+
+	if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA"))
+		return FALSE;
+
+	DBG(DBG_NATT,
+		DBG_dump("NAT-OA (S):", ip_val, ip_len);
+	);
+
+	close_output_pbs(&pbs);
+	return TRUE;
+}
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport)
+{
+	const char *mth = NULL, *rslt = NULL;
+	switch (nt & NAT_TRAVERSAL_METHOD) {
+		case LELEM(NAT_TRAVERSAL_IETF_00_01):
+			mth = natt_methods[0];
+			break;
+		case LELEM(NAT_TRAVERSAL_IETF_02_03):
+			mth = natt_methods[1];
+			break;
+		case LELEM(NAT_TRAVERSAL_RFC):
+			mth = natt_methods[2];
+			break;
+	}
+	switch (nt & NAT_T_DETECTED) {
+		case 0:
+			rslt = "no NAT detected";
+			break;
+		case LELEM(NAT_TRAVERSAL_NAT_BHND_ME):
+			rslt = "i am NATed";
+			break;
+		case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+			rslt = "peer is NATed";
+			break;
+		case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
+			rslt = "both are NATed";
+			break;
+	}
+	loglog(RC_LOG_SERIOUS,
+		"NAT-Traversal: Result using %s: %s",
+		mth ? mth : "unknown method",
+		rslt ? rslt : "unknown result"
+		);
+	if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)) &&
+		(sport == IKE_UDP_PORT) &&
+		((nt & NAT_T_WITH_PORT_FLOATING)==0)) {
+		loglog(RC_LOG_SERIOUS,
+			"Warning: peer is NATed but source port is still udp/%d. "
+			"Ipsec-passthrough NAT device suspected -- NAT-T may not work.",
+			IKE_UDP_PORT
+		);
+	}
+}
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type)
+{
+	int r;
+	r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type));
+	if ((r<0) && (errno == ENOPROTOOPT)) {
+		loglog(RC_LOG_SERIOUS,
+			"NAT-Traversal: ESPINUDP(%d) not supported by kernel -- "
+			"NAT-T disabled", type);
+		disable_nat_traversal();
+	}
+	return r;
+}
+
+void nat_traversal_new_ka_event (void)
+{
+	if (_ka_evt) return;  /* Event already schedule */
+	event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL);
+	_ka_evt = 1;
+}
+
+static void nat_traversal_send_ka (struct state *st)
+{
+	static unsigned char ka_payload = 0xff;
+	chunk_t sav;
+
+	DBG(DBG_NATT,
+		DBG_log("ka_event: send NAT-KA to %s:%d",
+			ip_str(&st->st_connection->that.host_addr),
+			st->st_connection->that.host_port);
+	);
+
+	/** save state chunk */
+	setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len);
+
+	/** send keep alive */
+	setchunk(st->st_tpacket, &ka_payload, 1);
+	_send_packet(st, "NAT-T Keep Alive", FALSE);
+
+	/** restore state chunk */
+	setchunk(st->st_tpacket, sav.ptr, sav.len);
+}
+
+/**
+ * Find ISAKMP States with NAT-T and send keep-alive
+ */
+static void nat_traversal_ka_event_state (struct state *st, void *data)
+{
+	unsigned int *_kap_st = (unsigned int *)data;
+	const struct connection *c = st->st_connection;
+	if (!c) return;
+	if ( ((st->st_state == STATE_MAIN_R3) ||
+			(st->st_state == STATE_MAIN_I4)) &&
+		(st->nat_traversal & NAT_T_DETECTED) &&
+		((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || (_force_ka))
+		) {
+		/**
+		 * - ISAKMP established
+		 * - NAT-Traversal detected
+		 * - NAT-KeepAlive needed (we are NATed)
+		 */
+		if (c->newest_isakmp_sa != st->st_serialno) {
+			/** 
+			 * if newest is also valid, ignore this one, we will only use
+			 * newest. 
+			 */
+			struct state *st_newest;
+			st_newest = state_with_serialno(c->newest_isakmp_sa);
+			if ((st_newest) && ((st_newest->st_state==STATE_MAIN_R3) ||
+				(st_newest->st_state==STATE_MAIN_I4)) &&
+				(st_newest->nat_traversal & NAT_T_DETECTED) &&
+				((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))
+				|| (_force_ka))) {
+				return;
+			}
+		}
+		set_cur_state(st);
+		nat_traversal_send_ka(st);
+		reset_cur_state();
+		(*_kap_st)++;
+	}
+}
+
+void nat_traversal_ka_event (void)
+{
+	unsigned int _kap_st = 0;
+
+	_ka_evt = 0;  /* ready to be reschedule */
+
+	for_each_state((void *)nat_traversal_ka_event_state, &_kap_st);
+
+	if (_kap_st) {
+		/**
+		 * If there are still states who needs Keep-Alive, schedule new event
+		 */
+		nat_traversal_new_ka_event();
+	}
+}
+
+struct _new_mapp_nfo {
+	ip_address addr;
+	u_int16_t sport, dport;
+};
+
+static void nat_traversal_find_new_mapp_state (struct state *st, void *data)
+{
+	struct connection *c = st->st_connection;
+	struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data;
+
+	if ((c) && sameaddr(&c->that.host_addr, &(nfo->addr)) &&
+		(c->that.host_port == nfo->sport)) {
+
+		/**
+		 * Change host port
+		 */
+		c->that.host_port = nfo->dport;
+
+		if (IS_IPSEC_SA_ESTABLISHED(st->st_state) ||
+			IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) {
+			if (!update_ipsec_sa(st)) {
+				/**
+				 * If ipsec update failed, restore old port or we'll
+				 * not be able to update anymore.
+				 */
+				c->that.host_port = nfo->sport;
+			}
+		}
+	}
+}
+
+static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport,
+	const ip_address *dst, u_int16_t dport)
+{
+	char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF];
+	struct _new_mapp_nfo nfo;
+
+	addrtot(src, 0, srca, ADDRTOT_BUF);
+	addrtot(dst, 0, dsta, ADDRTOT_BUF);
+
+	if (!sameaddr(src, dst)) {
+		loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: "
+			"address change currently not supported [%s:%d,%s:%d]",
+			srca, sport, dsta, dport);
+		return -1;
+	}
+
+	if (sport == dport) {
+		/* no change */
+		return 0;
+	}
+
+	DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport);
+
+	nfo.addr = *src;
+	nfo.sport = sport;
+	nfo.dport = dport;
+
+	for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo);
+
+	return 0;
+}
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st)
+{
+	struct connection *c = st ? st->st_connection : NULL;
+	struct iface *i = NULL;
+
+	if ((st == NULL) || (c == NULL)) {
+		return;
+	}
+
+	if (md) {
+		/**
+		 * If source port has changed, update (including other states and
+		 * established kernel SA)
+		 */
+		if (c->that.host_port != md->sender_port) {
+			nat_traversal_new_mapping(&c->that.host_addr, c->that.host_port,
+				&c->that.host_addr, md->sender_port);
+		}
+
+		/**
+		 * If interface type has changed, update local port (500/4500)
+		 */
+		if (((c->this.host_port == NAT_T_IKE_FLOAT_PORT) &&
+			 (md->iface->ike_float == FALSE)) ||
+			((c->this.host_port != NAT_T_IKE_FLOAT_PORT) &&
+			 (md->iface->ike_float == TRUE))) {
+			c->this.host_port = (md->iface->ike_float == TRUE)
+				? NAT_T_IKE_FLOAT_PORT : pluto_port;
+			DBG(DBG_NATT,
+				DBG_log("NAT-T: updating local port to %d", c->this.host_port);
+			);
+		}
+	}
+
+	/**
+	 * If we're initiator and NAT-T (with port floating) is detected, we
+	 * need to change port (MAIN_I3 or QUICK_I1)
+	 */
+	if (((st->st_state == STATE_MAIN_I3) || (st->st_state == STATE_QUICK_I1)) &&
+		(st->nat_traversal & NAT_T_WITH_PORT_FLOATING) &&
+		(st->nat_traversal & NAT_T_DETECTED) &&
+		(c->this.host_port != NAT_T_IKE_FLOAT_PORT)) {
+		DBG(DBG_NATT,
+			DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT);
+		);
+		c->this.host_port = NAT_T_IKE_FLOAT_PORT;
+		c->that.host_port = NAT_T_IKE_FLOAT_PORT;
+		/*
+		 * Also update pending connections or they will be deleted if uniqueids
+		 * option is set.
+		 */
+		update_pending(st, st);
+	}
+
+	/**
+	 * Find valid interface according to local port (500/4500)
+	 */
+	if (((c->this.host_port == NAT_T_IKE_FLOAT_PORT) &&
+		 (c->interface->ike_float == FALSE)) ||
+		((c->this.host_port != NAT_T_IKE_FLOAT_PORT) &&
+		 (c->interface->ike_float == TRUE))) {
+		for (i = interfaces; i !=  NULL; i = i->next) {
+			if ((sameaddr(&c->interface->addr, &i->addr)) &&
+				(i->ike_float != c->interface->ike_float)) {
+				DBG(DBG_NATT,
+					DBG_log("NAT-T: using interface %s:%d", i->rname,
+						i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port);
+				);
+				c->interface = i;
+				break;
+			}
+		}
+	}
+}
+
+struct _new_klips_mapp_nfo {
+	struct sadb_sa *sa;
+	ip_address src, dst;
+	u_int16_t sport, dport;
+};
+
+static void nat_t_new_klips_mapp (struct state *st, void *data)
+{
+	struct connection *c = st->st_connection;
+	struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data;
+
+	if ((c) && (st->st_esp.present) &&
+		sameaddr(&c->that.host_addr, &(nfo->src)) &&
+		(st->st_esp.our_spi == nfo->sa->sadb_sa_spi)) {
+		nat_traversal_new_mapping(&c->that.host_addr, c->that.host_port,
+			&(nfo->dst), nfo->dport);
+	}
+}
+
+void process_pfkey_nat_t_new_mapping(
+	struct sadb_msg *msg __attribute__ ((unused)),
+	struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+	struct _new_klips_mapp_nfo nfo;
+	struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
+	struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
+	struct sockaddr *srca, *dsta;
+	err_t ugh = NULL;
+
+	nfo.sa = (void *) extensions[SADB_EXT_SA];
+
+	if ((!nfo.sa) || (!srcx) || (!dstx)) {
+		log("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: "
+			"got NULL params");
+		return;
+	}
+
+	srca = ((struct sockaddr *)(void *)&srcx[1]);
+	dsta = ((struct sockaddr *)(void *)&dstx[1]);
+
+	if ((srca->sa_family != AF_INET) || (dsta->sa_family != AF_INET)) {
+		ugh = "only AF_INET supported";
+	}
+	else {
+		char text_said[SATOT_BUF];
+		char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF];
+		ip_said said;
+
+		initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr,
+			sizeof(((const struct sockaddr_in *)srca)->sin_addr),
+			srca->sa_family, &(nfo.src));
+		nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port);
+		initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr,
+			sizeof(((const struct sockaddr_in *)dsta)->sin_addr),
+			dsta->sa_family, &(nfo.dst));
+		nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port);
+
+		DBG(DBG_NATT,
+			initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said);
+			satot(&said, 0, text_said, SATOT_BUF);
+			addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF);
+			addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF);
+			DBG_log("new klips mapping %s %s:%d %s:%d",
+				text_said, _srca, nfo.sport, _dsta, nfo.dport);
+		);
+
+		for_each_state((void *)nat_t_new_klips_mapp, &nfo);
+	}
+
+	if (ugh != NULL)
+		log("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh);
+}
+
+#endif
+
diff -uNr freeswan-2.02.stock/programs/pluto/nat_traversal.h freeswan-2.02/programs/pluto/nat_traversal.h
--- freeswan-2.02.stock/programs/pluto/nat_traversal.h	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/nat_traversal.h	2003-10-11 09:16:16.000000000 -0400
@@ -0,0 +1,151 @@
+/* FreeS/WAN NAT-Traversal
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: nat_traversal.h,v 1.9 2003/01/02 15:46:15 mathieu Exp $
+ */
+
+#ifndef _NAT_TRAVERSAL_H_
+#define _NAT_TRAVERSAL_H_
+
+#define NAT_TRAVERSAL_IETF_00_01     1
+#define NAT_TRAVERSAL_IETF_02_03     2
+#define NAT_TRAVERSAL_RFC            3
+
+#define NAT_TRAVERSAL_NAT_BHND_ME    30
+#define NAT_TRAVERSAL_NAT_BHND_PEER  31
+
+#define NAT_TRAVERSAL_METHOD  (0xffffffff - LELEM(30) - LELEM(31))
+
+/**
+ * NAT-Traversal methods which need NAT-D
+ */
+#define NAT_T_WITH_NATD \
+	( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+	LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which need NAT-OA
+ */
+#define NAT_T_WITH_NATOA \
+	( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+	LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which use NAT-KeepAlive
+ */
+#define NAT_T_WITH_KA \
+	( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
+	LELEM(NAT_TRAVERSAL_RFC) )
+/**
+ * NAT-Traversal methods which use floating port
+ */
+#define NAT_T_WITH_PORT_FLOATING \
+	( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal methods which use officials values (RFC)
+ */
+#define NAT_T_WITH_RFC_VALUES \
+	( LELEM(NAT_TRAVERSAL_RFC) )
+
+/**
+ * NAT-Traversal detected
+ */
+#define NAT_T_DETECTED \
+	( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) )
+
+/**
+ * NAT-T Port Floating
+ */
+#define NAT_T_IKE_FLOAT_PORT     4500
+
+void init_nat_traversal (bool activate, unsigned int keep_alive_period,
+	bool fka, bool spf);
+
+extern bool nat_traversal_enabled;
+extern bool nat_traversal_support_port_floating;
+
+/**
+ * NAT-D
+ */
+void nat_traversal_natd_lookup(struct msg_digest *md);
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
+	struct msg_digest *md);
+#endif
+
+/**
+ * NAT-OA
+ */
+void nat_traversal_natoa_lookup(struct msg_digest *md);
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
+	struct state *st);
+#endif
+
+/**
+ * NAT-keep_alive
+ */
+void nat_traversal_new_ka_event (void);
+void nat_traversal_ka_event (void);
+
+void nat_traversal_show_result (u_int32_t nt, u_int16_t sport);
+
+int nat_traversal_espinudp_socket (int sk, u_int32_t type);
+
+/**
+ * Vendor ID
+ */
+#ifndef PB_STREAM_UNDEFINED
+bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs);
+#endif
+u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid);
+
+void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st);
+
+/**
+ * New NAT mapping
+ */
+#ifdef __PFKEY_V2_H
+void process_pfkey_nat_t_new_mapping(
+	struct sadb_msg *,
+	struct sadb_ext *[SADB_EXT_MAX + 1]);
+#endif
+
+/**
+ * IKE port floating
+ */
+bool
+nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in);
+
+/**
+ * Encapsulation mode macro (see demux.c)
+ */
+#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \
+	((st)->nat_traversal & NAT_T_DETECTED) \
+		? ( ((nat_t_policy) & POLICY_TUNNEL) \
+			? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
+				? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \
+				: (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \
+			  ) \
+			: ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
+				? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \
+				: (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \
+			  ) \
+		  ) \
+		: ( ((st)->st_policy & POLICY_TUNNEL) \
+			? (ENCAPSULATION_MODE_TUNNEL) \
+			: (ENCAPSULATION_MODE_TRANSPORT) \
+		  ) \
+	)
+
+#endif /* _NAT_TRAVERSAL_H_ */
+
diff -uNr freeswan-2.02.stock/programs/pluto/packet.c freeswan-2.02/programs/pluto/packet.c
--- freeswan-2.02.stock/programs/pluto/packet.c	2003-05-24 22:35:51.000000000 -0400
+++ freeswan-2.02/programs/pluto/packet.c	2003-10-11 09:16:16.000000000 -0400
@@ -517,6 +517,42 @@
  */
 struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) };
 
+#ifdef NAT_TRAVERSAL
+/* ISAKMP NAT-Traversal NAT-D
+ * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2
+ *
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload  !   RESERVED    !         Payload Length        !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !                 HASH of the address and port                  !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) };
+
+/* ISAKMP NAT-Traversal NAT-OA
+ * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2
+ *
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ! Next Payload  !   RESERVED    !         Payload Length        !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !   ID Type     !   RESERVED    !            RESERVED           !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * !         IPv4 (4 octets) or IPv6 address (16 octets)           !
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+static field_desc isanat_oa_fields[] = {
+    { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+    { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+    { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+    { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
+    { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL },
+    { ft_end, 0, NULL, NULL }
+};
+
+struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
+#endif
 
 /* descriptor for each payload type
  *
@@ -541,6 +577,11 @@
     &isakmp_notification_desc,		/* 11 ISAKMP_NEXT_N (Notification) */
     &isakmp_delete_desc,		/* 12 ISAKMP_NEXT_D (Delete) */
     &isakmp_vendor_id_desc,		/* 13 ISAKMP_NEXT_VID (Vendor ID) */
+#ifdef NAT_TRAVERSAL
+	NULL,
+	&isakmp_nat_d,              /* 15=130 ISAKMP_NEXT_NATD (NAT-D) */
+	&isakmp_nat_oa,             /* 16=131 ISAKMP_NEXT_NATOA (NAT-OA) */
+#endif
 };
 
 void
@@ -1085,6 +1126,38 @@
     return TRUE;
 }
 
+#if 1
+bool
+out_modify_previous_np(u_int8_t np, pb_stream *outs)
+{
+	size_t len = (outs->cur - outs->start), offset;
+	if (len < sizeof(struct isakmp_hdr)) {
+		return FALSE;
+	}
+	else if (len == sizeof(struct isakmp_hdr)) {
+		struct isakmp_hdr *hdr = (struct isakmp_hdr *)outs->start;
+		hdr->isa_np = np;
+		return TRUE;
+	}
+	else {
+		struct isakmp_generic *hdr;
+		for (offset = sizeof(struct isakmp_hdr); offset < len ;
+			offset += ntohs(hdr->isag_length)) {
+			if ((len - offset) < sizeof(struct isakmp_generic))
+				return FALSE;
+			hdr = (struct isakmp_generic *)(outs->start+offset);
+			if ((len - offset) < ntohs(hdr->isag_length))
+				return FALSE;
+			if ((len - offset) == ntohs(hdr->isag_length)) {
+				hdr->isag_np = np;
+				return TRUE;
+			}
+		}
+	}
+	return FALSE;
+}
+#endif
+
 bool
 out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name)
 {
diff -uNr freeswan-2.02.stock/programs/pluto/packet.h freeswan-2.02/programs/pluto/packet.h
--- freeswan-2.02.stock/programs/pluto/packet.h	2002-07-30 22:45:43.000000000 -0400
+++ freeswan-2.02/programs/pluto/packet.h	2003-10-11 09:16:16.000000000 -0400
@@ -93,6 +93,9 @@
     pb_stream *outs, pb_stream *obj_pbs);
 extern bool out_generic_raw(u_int8_t np, struct_desc *sd,
     pb_stream *outs, void *bytes, size_t len, const char *name);
+#if 1
+extern bool out_modify_previous_np(u_int8_t np, pb_stream *outs);
+#endif
 #define out_generic_chunk(np, sd, outs, ch, name) \
 	out_generic_raw(np, sd, outs, (ch).ptr, (ch).len, name)
 extern bool out_zero(size_t len, pb_stream *outs, const char *name);
@@ -580,6 +583,21 @@
  */
 extern struct_desc isakmp_vendor_id_desc;
 
+#ifdef NAT_TRAVERSAL
+struct isakmp_nat_oa
+{
+    u_int8_t    isanoa_np;
+    u_int8_t    isanoa_reserved_1;
+    u_int16_t   isanoa_length;
+    u_int8_t    isanoa_idtype;
+    u_int8_t    isanoa_reserved_2;
+    u_int16_t   isanoa_reserved_3;
+};
+
+extern struct_desc isakmp_nat_d;
+extern struct_desc isakmp_nat_oa;
+#endif
+
 /* union of all payloads */
 
 union payload {
@@ -593,6 +611,9 @@
     struct isakmp_ipsec_id ipsec_id;	/* Quick Mode */
     struct isakmp_notification notification;
     struct isakmp_delete delete;
+#ifdef NAT_TRAVERSAL
+    struct isakmp_nat_oa nat_oa;
+#endif
 };
 
 /* descriptor for each payload type
diff -uNr freeswan-2.02.stock/programs/pluto/plutomain.c freeswan-2.02/programs/pluto/plutomain.c
--- freeswan-2.02.stock/programs/pluto/plutomain.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/plutomain.c	2003-10-11 09:23:11.000000000 -0400
@@ -61,6 +61,14 @@
 #include "md5.h"
 #include "crypto.h"	/* requires sha1.h and md5.h */
 
+#ifdef VIRTUAL_IP
+#include "virtual.h"
+#endif
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
 static void
 usage(const char *mess)
 {
@@ -104,6 +112,18 @@
 	    " [--debug-dns]"
 	    " [ --debug-private]"
 #endif
+#ifdef NAT_TRAVERSAL
+            " [ --debug-nat_t]"
+            " \\\n\t"
+            "[--nat_traversal] [--keep_alive <delay_sec>]"
+            " \\\n\t"
+               "[--force_keepalive] [--disable_port_floating]"
+#endif
+#ifdef VIRTUAL_IP
+            " \\\n\t"
+            "[--virtual_private <network_list>]"
+#endif
+
 	    "\n"
 	"FreeS/WAN %s\n"
 	, ipsec_version_code());
@@ -184,6 +204,15 @@
     bool fork_desired = TRUE;
     bool log_to_stderr_desired = FALSE;
     int lockfd;
+#ifdef NAT_TRAVERSAL
+    bool nat_traversal = FALSE;
+    bool nat_t_spf = TRUE;  /* support port floating */
+    unsigned int keep_alive = 0;
+    bool force_keepalive = FALSE;
+#endif
+#ifdef VIRTUAL_IP
+    char *virtual_private = NULL;
+#endif
 
     /* handle arguments */
     for (;;)
@@ -233,6 +262,16 @@
 	    { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
 	    { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
 #endif
+#ifdef NAT_TRAVERSAL
+	    { "nat_traversal", no_argument, NULL, '1' },
+	    { "keep_alive", required_argument, NULL, '2' },
+	    { "force_keepalive", no_argument, NULL, '3' },
+	    { "disable_port_floating", no_argument, NULL, '4' },
+	    { "debug-nat_t", no_argument, NULL, '5' },
+#endif
+#ifdef VIRTUAL_IP
+	    { "virtual_private", required_argument, NULL, '6' },
+#endif
 	    { 0,0,0,0 }
 	    };
 	/* Note: we don't like the way short options get parsed
@@ -372,6 +411,29 @@
 	    continue;
 #endif
 
+#ifdef NAT_TRAVERSAL
+	case '1':	/* --nat_traversal */
+	    nat_traversal = TRUE;
+	    continue;
+	case '2':	/* --keep_alive */
+	    keep_alive = atoi(optarg);
+	    continue;
+	case '3':	/* --force_keepalive */
+	    force_keepalive = TRUE;
+	    continue;
+	case '4':	/* --disable_port_floating */
+	    nat_t_spf = FALSE;
+	    continue;
+	case '5':	/* --debug-nat_t */
+	    base_debugging |= DBG_NATT;
+	    continue;
+#endif
+#ifdef VIRTUAL_IP
+	case '6':	/* --virtual_private */
+	    virtual_private = optarg;
+	    continue;
+#endif
+
 	default:
 #ifdef DEBUG
 	    if (c >= DBG_OFFSET)
@@ -520,6 +582,13 @@
 #endif
     }
 
+#ifdef NAT_TRAVERSAL
+    init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
+#endif
+
+#ifdef VIRTUAL_IP
+    init_virtual_ip(virtual_private);
+#endif
     init_rnd_pool();
     init_secret();
     init_states();
diff -uNr freeswan-2.02.stock/programs/pluto/rcv_whack.c freeswan-2.02/programs/pluto/rcv_whack.c
--- freeswan-2.02.stock/programs/pluto/rcv_whack.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/rcv_whack.c	2003-10-11 09:28:36.000000000 -0400
@@ -308,10 +308,16 @@
 	|| !unpack_str(&msg.left.cert)		/* string  3 */
 	|| !unpack_str(&msg.left.ca)		/* string  4 */
 	|| !unpack_str(&msg.left.updown)	/* string  5 */
+#ifdef VIRTUAL_IP
+        || !unpack_str(&msg.left.virt)
+#endif
 	|| !unpack_str(&msg.right.id)		/* string  6 */
 	|| !unpack_str(&msg.right.cert)		/* string  7 */
 	|| !unpack_str(&msg.right.ca)		/* string  8 */
 	|| !unpack_str(&msg.right.updown)	/* string  9 */
+#ifdef VIRTUAL_IP
+        || !unpack_str(&msg.right.virt)
+#endif
 	|| !unpack_str(&msg.keyid)		/* string 10 */
 	|| !unpack_str(&msg.myid)		/* string 11 */
 	|| str_roof - next_str != (ptrdiff_t)msg.keyval.len)	/* check chunk */
diff -uNr freeswan-2.02.stock/programs/pluto/server.c freeswan-2.02/programs/pluto/server.c
--- freeswan-2.02.stock/programs/pluto/server.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/server.c	2003-10-11 09:39:19.000000000 -0400
@@ -67,6 +67,10 @@
 #include <pfkeyv2.h>
 #include <pfkey.h>
 
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
 /*
  *  Server main loop and socket initialization routines.
  */
@@ -449,6 +453,86 @@
     return rifaces;
 }
 
+#if 1
+static int
+create_socket(struct raw_iface *ifp, const char *v_name, int port)
+{
+    int fd = socket(addrtypeof(&ifp->addr), SOCK_DGRAM, IPPROTO_UDP);
+    int fcntl_flags;
+
+    if (fd < 0)
+    {
+	log_errno((e, "socket() in process_raw_ifaces()"));
+	return -1;
+    }
+
+#if 1
+    /* Set socket Nonblocking */
+    if ((fcntl_flags=fcntl(fd, F_GETFL)) >= 0) {
+	if (!(fcntl_flags & O_NONBLOCK)) {
+	    fcntl_flags |= O_NONBLOCK;
+	    fcntl(fd, F_SETFL, fcntl_flags);
+	}
+    }
+#endif
+
+    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+    {
+	log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()"));
+	close(fd);
+	return -1;
+    }
+
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR
+    , (const void *)&on, sizeof(on)) < 0)
+    {
+	log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()"));
+	close(fd);
+	return -1;
+    }
+
+    /* To improve error reporting.  See ip(7). */
+#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
+    if (setsockopt(fd, SOL_IP, IP_RECVERR
+    , (const void *)&on, sizeof(on)) < 0)
+    {
+	log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()"));
+	close(fd);
+	return -1;
+    }
+#endif
+
+    /* With IPv6, there is no fragmentation after
+     * it leaves our interface.  PMTU discovery
+     * is mandatory but doesn't work well with IKE (why?).
+     * So we must set the IPV6_USE_MIN_MTU option.
+     * See draft-ietf-ipngwg-rfc2292bis-01.txt 11.1
+     */
+#ifdef IPV6_USE_MIN_MTU	/* YUCK: not always defined */
+    if (addrtypeof(&ifp->addr) == AF_INET6
+    && setsockopt(fd, SOL_SOCKET, IPV6_USE_MIN_MTU
+      , (const void *)&on, sizeof(on)) < 0)
+    {
+	log_errno((e, "setsockopt IPV6_USE_MIN_MTU in process_raw_ifaces()"));
+	close(fd);
+	return -1;
+    }
+#endif
+
+    setportof(htons(port), &ifp->addr);
+    if (bind(fd, sockaddrof(&ifp->addr), sockaddrlenof(&ifp->addr)) < 0)
+    {
+	log_errno((e, "bind() for %s/%s %s:%u in process_raw_ifaces()"
+	    , ifp->name, v_name
+	    , ip_str(&ifp->addr), (unsigned) port));
+	close(fd);
+	return -1;
+    }
+    setportof(htons(pluto_port), &ifp->addr);
+    return fd;
+}
+#endif
+
 static void
 process_raw_ifaces(struct raw_iface *rifaces)
 {
@@ -550,61 +634,16 @@
 		if (q == NULL)
 		{
 		    /* matches nothing -- create a new entry */
-		    int fd = socket(addrtypeof(&ifp->addr), SOCK_DGRAM, IPPROTO_UDP);
-
+		    int fd = create_socket(ifp, v->name, pluto_port);
 		    if (fd < 0)
-		    {
-			log_errno((e, "socket() in process_raw_ifaces()"));
-			break;
-		    }
-
-		    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
-		    {
-			log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()"));
 			break;
-		    }
-
-		    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR
-		    , (const void *)&on, sizeof(on)) < 0)
-		    {
-			log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()"));
-			break;
-		    }
 
-		    /* To improve error reporting.  See ip(7). */
-#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE)
-		    if (setsockopt(fd, SOL_IP, IP_RECVERR
-		    , (const void *)&on, sizeof(on)) < 0)
-		    {
-			log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()"));
-			break;
+#ifdef NAT_TRAVERSAL
+		    if (nat_traversal_enabled) {
+			nat_traversal_espinudp_socket(fd, ESPINUDP_WITH_NON_IKE);
 		    }
 #endif
 
-		    /* With IPv6, there is no fragmentation after
-		     * it leaves our interface.  PMTU discovery
-		     * is mandatory but doesn't work well with IKE (why?).
-		     * So we must set the IPV6_USE_MIN_MTU option.
-		     * See draft-ietf-ipngwg-rfc2292bis-01.txt 11.1
-		     */
-#ifdef IPV6_USE_MIN_MTU	/* YUCK: not always defined */
-		    if (addrtypeof(&ifp->addr) == AF_INET6
-		    && setsockopt(fd, SOL_SOCKET, IPV6_USE_MIN_MTU
-		      , (const void *)&on, sizeof(on)) < 0)
-		    {
-			log_errno((e, "setsockopt IPV6_USE_MIN_MTU in process_raw_ifaces()"));
-			break;
-		    }
-#endif
-		    setportof(htons(pluto_port), &ifp->addr);
-		    if (bind(fd, sockaddrof(&ifp->addr), sockaddrlenof(&ifp->addr)) < 0)
-		    {
-			log_errno((e, "bind() for %s/%s %s:%u in process_raw_ifaces()"
-			    , ifp->name, v->name
-			    , ip_str(&ifp->addr), (unsigned) pluto_port));
-			break;
-		    }
-
 		    q = alloc_thing(struct iface, "struct iface");
 		    q->rname = clone_str(ifp->name, "real device name");
 		    q->vname = clone_str(v->name, "virtual device name");
@@ -615,6 +654,29 @@
 		    interfaces = q;
 		    plog("adding interface %s/%s %s"
 			, q->vname, q->rname, ip_str(&q->addr));
+
+#ifdef NAT_TRAVERSAL
+                    if (nat_traversal_support_port_floating) {
+                        fd = create_socket(ifp, v->name, NAT_T_IKE_FLOAT_PORT);
+                        if (fd < 0)
+                            break;
+                        nat_traversal_espinudp_socket(fd,
+                            ESPINUDP_WITH_NON_ESP);
+                        q = alloc_thing(struct iface, "struct iface");
+                        q->rname = clone_str(ifp->name, "real device name");
+                        q->vname = clone_str(v->name, "virtual device name");
+                        q->addr = ifp->addr;
+                        setportof(htons(NAT_T_IKE_FLOAT_PORT), &q->addr);
+                        q->fd = fd;
+                        q->next = interfaces;
+                        q->change = IFN_ADD;
+                        q->ike_float = TRUE;
+                        interfaces = q;
+                        plog("adding interface %s/%s %s:%d",
+                            q->vname, q->rname, ip_str(&q->addr), NAT_T_IKE_FLOAT_PORT);
+                    }
+#endif
+
 		    break;
 		}
 
@@ -625,6 +687,17 @@
 		{
 		    /* matches -- rejuvinate old entry */
 		    q->change = IFN_KEEP;
+
+#ifdef NAT_TRAVERSAL
+                    /* look for other interfaces to keep (due to NAT-T) */
+                    for (q = q->next ; q ; q = q->next) {
+                        if (streq(q->rname, ifp->name)
+                            && streq(q->vname, v->name)
+                            && sameaddr(&q->addr, &ifp->addr)) {
+                                q->change = IFN_KEEP;
+                            }
+                    }
+#endif
 		    break;
 		}
 
diff -uNr freeswan-2.02.stock/programs/pluto/server.h freeswan-2.02/programs/pluto/server.h
--- freeswan-2.02.stock/programs/pluto/server.h	2003-05-10 21:52:56.000000000 -0400
+++ freeswan-2.02/programs/pluto/server.h	2003-10-11 09:16:16.000000000 -0400
@@ -40,6 +40,9 @@
     ip_address addr;	/* interface IP address */
     int fd;	/* file descriptor of socket for IKE UDP messages */
     struct iface *next;
+#ifdef NAT_TRAVERSAL
+    bool ike_float;
+#endif
     enum { IFN_ADD, IFN_KEEP, IFN_DELETE } change;
 };
 
diff -uNr freeswan-2.02.stock/programs/pluto/spdb.c freeswan-2.02/programs/pluto/spdb.c
--- freeswan-2.02.stock/programs/pluto/spdb.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/spdb.c	2003-10-11 09:16:16.000000000 -0400
@@ -47,6 +47,10 @@
 #define AD(x) x, elemsof(x)	/* Array Description */
 #define AD_NULL NULL, 0
 
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
 /**************** Oakely (main mode) SA database ****************/
 
 /* arrays of attributes for transforms, preshared key */
@@ -585,9 +589,35 @@
 		    if (p->protoid != PROTO_IPCOMP
 		    || st->st_policy & POLICY_TUNNEL)
 		    {
+#ifdef NAT_TRAVERSAL
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+			if ((st->nat_traversal & NAT_T_DETECTED) &&
+				(!(st->st_policy & POLICY_TUNNEL))) {
+				/* Inform user that we will not respect policy and only
+				 * propose Tunnel Mode
+				 */
+				loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
+					"Transport Mode not allowed due to security concerns -- "
+					"using Tunnel mode");
+			}
+#endif
+#endif
 			out_attr(ENCAPSULATION_MODE
+#ifdef NAT_TRAVERSAL
+#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+			    , NAT_T_ENCAPSULATION_MODE(st,st->st_policy)
+#else
+				/* If NAT-T is detected, use UDP_TUNNEL as long as Transport
+				 * Mode has security concerns.
+				 *
+				 * User has been informed of that
+				 */
+			    , NAT_T_ENCAPSULATION_MODE(st,POLICY_TUNNEL)
+#endif
+#else /* ! NAT_TRAVERSAL */
 			    , st->st_policy & POLICY_TUNNEL
 			      ? ENCAPSULATION_MODE_TUNNEL : ENCAPSULATION_MODE_TRANSPORT
+#endif
 			    , attr_desc, attr_val_descs
 			    , &trans_pbs);
 		    }
@@ -1329,7 +1359,89 @@
 		break;
 	    case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV:
 		ipcomp_inappropriate = FALSE;
+#ifdef NAT_TRAVERSAL
+		switch (val) {
+			case ENCAPSULATION_MODE_TUNNEL:
+			case ENCAPSULATION_MODE_TRANSPORT:
+				if (st->nat_traversal & NAT_T_DETECTED) {
+					loglog(RC_LOG_SERIOUS,
+						"%s must only be used if "
+						"NAT-Traversal is not detected",
+						enum_name(&enc_mode_names, val));
+					/*
+					 * Accept it anyway because SSH-Sentinel does not
+					 * use UDP_TUNNEL or UDP_TRANSPORT for the diagnostic.
+					 *
+					 * remove when SSH-Sentinel is fixed
+					 */
+#ifdef I_DONT_CARE_OF_SSH_SENTINEL
+					return FALSE;
+#endif
+				}
+				attrs->encapsulation = val;
+				break;
+			case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS:
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+				loglog(RC_LOG_SERIOUS,
+					"NAT-Traversal: Transport mode disabled due "
+					"to security concerns");
+				return FALSE;
+				break;
+#endif
+			case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS:
+				if (st->nat_traversal & NAT_T_WITH_RFC_VALUES) {
+					loglog(RC_LOG_SERIOUS,
+						"%s must only be used with old IETF drafts",
+						enum_name(&enc_mode_names, val));
+					return FALSE;
+				}
+				else if (st->nat_traversal & NAT_T_DETECTED) {
+					attrs->encapsulation = val - ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS + ENCAPSULATION_MODE_TUNNEL;
+				}
+				else {
+					loglog(RC_LOG_SERIOUS,
+						"%s must only be used if "
+						"NAT-Traversal is detected",
+						enum_name(&enc_mode_names, val));
+					return FALSE;
+				}
+				break;
+			case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC:
+#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT
+				loglog(RC_LOG_SERIOUS,
+					"NAT-Traversal: Transport mode disabled due "
+					"to security concerns");
+				return FALSE;
+				break;
+#endif
+			case ENCAPSULATION_MODE_UDP_TUNNEL_RFC:
+				if ((st->nat_traversal & NAT_T_DETECTED) &&
+					(st->nat_traversal & NAT_T_WITH_RFC_VALUES)) {
+					attrs->encapsulation = val - ENCAPSULATION_MODE_UDP_TUNNEL_RFC + ENCAPSULATION_MODE_TUNNEL;
+				}
+				else if (st->nat_traversal & NAT_T_DETECTED) {
+					loglog(RC_LOG_SERIOUS,
+						"%s must only be used with NAT-T RFC",
+						enum_name(&enc_mode_names, val));
+					return FALSE;
+				}
+				else {
+					loglog(RC_LOG_SERIOUS,
+						"%s must only be used if "
+						"NAT-Traversal is detected",
+						enum_name(&enc_mode_names, val));
+					return FALSE;
+				}
+				break;
+			default:
+				loglog(RC_LOG_SERIOUS,
+					"unknown ENCAPSULATION_MODE %d in IPSec SA", val);
+				return FALSE;
+				break;
+		}
+#else
 		attrs->encapsulation = val;
+#endif
 		break;
 	    case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV:
 		attrs->auth = val;
diff -uNr freeswan-2.02.stock/programs/pluto/state.c freeswan-2.02/programs/pluto/state.c
--- freeswan-2.02.stock/programs/pluto/state.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/state.c	2003-10-11 09:16:16.000000000 -0400
@@ -511,6 +511,21 @@
     return nst;
 }
 
+#if 1
+void for_each_state(void *(f)(struct state *, void *data), void *data)
+{
+	struct state *st, *ocs = cur_state;
+	int i;
+	for (i=0; i<STATE_TABLE_SIZE; i++) {
+		for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) {
+			set_cur_state(st);
+			f(st, data);
+		}
+	}
+	cur_state = ocs;
+}
+#endif
+
 /*
  * Find a state object.
  */
diff -uNr freeswan-2.02.stock/programs/pluto/state.h freeswan-2.02/programs/pluto/state.h
--- freeswan-2.02.stock/programs/pluto/state.h	2003-06-15 22:21:13.000000000 -0400
+++ freeswan-2.02/programs/pluto/state.h	2003-10-11 09:16:16.000000000 -0400
@@ -199,6 +199,10 @@
     struct event      *st_event;               /* backpointer for certain events */
     struct state      *st_hashchain_next;      /* Next in list */
     struct state      *st_hashchain_prev;      /* Previous in list */
+#ifdef NAT_TRAVERSAL
+    u_int32_t         nat_traversal;
+    ip_address        nat_oa;
+#endif
 };
 
 /* global variables */
@@ -234,6 +238,10 @@
 
 extern void show_states_status(void);
 
+#if 1
+void for_each_state(void *(f)(struct state *, void *data), void *data);
+#endif
+
 extern void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi);
 extern ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st);
 extern void fmt_state(struct state *st, time_t n
diff -uNr freeswan-2.02.stock/programs/pluto/timer.c freeswan-2.02/programs/pluto/timer.c
--- freeswan-2.02.stock/programs/pluto/timer.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/timer.c	2003-10-11 09:16:16.000000000 -0400
@@ -44,6 +44,10 @@
 #include "timer.h"
 #include "whack.h"
 
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
 /* monotonic version of time(3) */
 time_t
 now(void)
@@ -405,6 +409,12 @@
 	    delete_state(st);
 	    break;
 
+#ifdef NAT_TRAVERSAL
+	case EVENT_NAT_T_KEEPALIVE:
+	    nat_traversal_ka_event();
+	    break;
+#endif
+
 	default:
 	    loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %s"
 		, enum_show(&timer_event_names, type));
diff -uNr freeswan-2.02.stock/programs/pluto/vendor.c freeswan-2.02/programs/pluto/vendor.c
--- freeswan-2.02.stock/programs/pluto/vendor.c	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/vendor.c	2003-10-11 09:46:14.000000000 -0400
@@ -0,0 +1,417 @@
+/* FreeS/WAN ISAKMP VendorID
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: vendor.c,v 1.16 2003/03/17 09:15:28 mathieu Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "md5.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "packet.h"
+#include "demux.h"
+#include "whack.h"
+#include "vendor.h"
+
+#ifdef NAT_TRAVERSAL
+#include "nat_traversal.h"
+#endif
+
+/**
+ * Unknown/Special VID:
+ *
+ * SafeNet SoftRemote 8.0.0:
+ *  47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e302e3020284275696c6420313029000000
+ *  >> 382e302e3020284275696c6420313029 = '8.0.0 (Build 10)'
+ *  da8e937880010000
+ *
+ * SafeNet SoftRemote 9.0.1
+ *  47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310392e302e3120284275696c6420313229000000
+ *  >> 392e302e3120284275696c6420313229 = '9.0.1 (Build 12)'
+ *  da8e937880010000
+ *
+ * Netscreen:
+ *  d6b45f82f24bacb288af59a978830ab7
+ *  cf49908791073fb46439790fdeb6aeed981101ab0000000500000300
+ *
+ * Cisco:
+ *  c32364b3b4f447eb17c488ab2a480a57
+ *  1f07f70eaa6514d3b0fa96542a500305
+ *  1f07f70eaa6514d3b0fa96542a500300
+ *  1f07f70eaa6514d3b0fa96542a500301 (VPN 3000 version 3.1 ??)
+ *  afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection ?)
+ *  6d761ddc26aceca1b0ed11fabbb860c4
+ *
+ * Microsoft L2TP (???):
+ *  47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e312e3020284275696c6420313029000000
+ *  >> 382e312e3020284275696c6420313029 = '8.1.0 (Build 10)'
+ *  3025dbd21062b9e53dc441c6aab5293600000000
+ *  da8e937880010000
+ *
+ * If someone know what they mean, mail me.
+ */
+
+#define MAX_LOG_VID_LEN    8
+
+#define VID_KEEP                   0x0000
+#define VID_MD5HASH                0x0001
+#define VID_STRING                 0x0002
+#define VID_FSWAN_HASH             0x0004
+
+#define VID_SUBSTRING_DUMPHEXA     0x0100
+#define VID_SUBSTRING_DUMPASCII    0x0200
+#define VID_SUBSTRING  (VID_SUBSTRING_DUMPHEXA | VID_SUBSTRING_DUMPASCII)
+
+struct vid_struct {
+	unsigned int id;
+	unsigned short flags;
+	const char *data;
+	const char *descr;
+	const char *vid;
+	unsigned int vid_len;
+};
+
+#define DEC_MD5_VID_D(id,str,descr) \
+	{ VID_##id, VID_MD5HASH, str, descr, NULL, 0 },
+#define DEC_MD5_VID(id,str) \
+	{ VID_##id, VID_MD5HASH, str, NULL, NULL, 0 },
+#define DEC_FSWAN_VID(id,str,descr) \
+	{ VID_##id, VID_FSWAN_HASH, str, descr, NULL, 0 },
+
+static struct vid_struct _vid_tab[] = {
+
+	/* Implementation names */
+
+	{ VID_OPENPGP, VID_STRING, "OpenPGP10171", "OpenPGP", NULL, 0 },
+
+	DEC_MD5_VID(KAME_RACOON, "KAME/racoon")
+
+	{ VID_MS_NT5, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA,
+		"MS NT5 ISAKMPOAKLEY", NULL, NULL, 0 },
+
+	DEC_MD5_VID(SSH_SENTINEL, "SSH Sentinel")
+	DEC_MD5_VID(SSH_SENTINEL_1_1, "SSH Sentinel 1.1")
+	DEC_MD5_VID(SSH_SENTINEL_1_2, "SSH Sentinel 1.2")
+	DEC_MD5_VID(SSH_SENTINEL_1_3, "SSH Sentinel 1.3")
+	DEC_MD5_VID(SSH_SENTINEL_1_4, "SSH Sentinel 1.4")
+	DEC_MD5_VID(SSH_SENTINEL_1_4_1, "SSH Sentinel 1.4.1")
+
+	/* These ones come from SSH vendors.txt */
+	DEC_MD5_VID(SSH_IPSEC_1_1_0,
+		"Ssh Communications Security IPSEC Express version 1.1.0")
+	DEC_MD5_VID(SSH_IPSEC_1_1_1,
+		"Ssh Communications Security IPSEC Express version 1.1.1")
+	DEC_MD5_VID(SSH_IPSEC_1_1_2,
+		"Ssh Communications Security IPSEC Express version 1.1.2")
+	DEC_MD5_VID(SSH_IPSEC_1_2_1,
+		"Ssh Communications Security IPSEC Express version 1.2.1")
+	DEC_MD5_VID(SSH_IPSEC_1_2_2,
+		"Ssh Communications Security IPSEC Express version 1.2.2")
+	DEC_MD5_VID(SSH_IPSEC_2_0_0,
+		"SSH Communications Security IPSEC Express version 2.0.0")
+	DEC_MD5_VID(SSH_IPSEC_2_1_0,
+		"SSH Communications Security IPSEC Express version 2.1.0")
+	DEC_MD5_VID(SSH_IPSEC_2_1_1,
+		"SSH Communications Security IPSEC Express version 2.1.1")
+	DEC_MD5_VID(SSH_IPSEC_2_1_2,
+		"SSH Communications Security IPSEC Express version 2.1.2")
+	DEC_MD5_VID(SSH_IPSEC_3_0_0,
+		"SSH Communications Security IPSEC Express version 3.0.0")
+	DEC_MD5_VID(SSH_IPSEC_3_0_1,
+		"SSH Communications Security IPSEC Express version 3.0.1")
+	DEC_MD5_VID(SSH_IPSEC_4_0_0,
+		"SSH Communications Security IPSEC Express version 4.0.0")
+	DEC_MD5_VID(SSH_IPSEC_4_0_1,
+		"SSH Communications Security IPSEC Express version 4.0.1")
+	DEC_MD5_VID(SSH_IPSEC_4_1_0,
+		"SSH Communications Security IPSEC Express version 4.1.0")
+	DEC_MD5_VID(SSH_IPSEC_4_2_0,
+		"SSH Communications Security IPSEC Express version 4.2.0")
+
+	/* note: md5('CISCO-UNITY') = 12f5f28c457168a9702d9fe274cc02d4 */
+	{ VID_CISCO_UNITY, VID_KEEP, NULL, "Cisco-Unity",
+		"\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00",
+		16 },
+
+	/**
+	 * Timestep VID seen:
+	 *   - 54494d455354455020312053475720313532302033313520322e303145303133
+	 *     = 'TIMESTEP 1 SGW 1520 315 2.01E013'
+	 */
+	{ VID_TIMESTEP, VID_STRING | VID_SUBSTRING_DUMPASCII, "TIMESTEP",
+		NULL, NULL, 0 },
+
+	DEC_FSWAN_VID(FSWAN_2_00_VID,
+		"Linux FreeS/WAN 2.00 PLUTO_SENDS_VENDORID",
+		"FreeS/WAN 2.00")
+	DEC_FSWAN_VID(FSWAN_2_00_X509_1_3_1_VID,
+		"Linux FreeS/WAN 2.00 X.509-1.3.1 PLUTO_SENDS_VENDORID",
+		"FreeS/WAN 2.00 (X.509-1.3.1)")
+	DEC_FSWAN_VID(FSWAN_2_00_X509_1_3_1_LDAP_VID,
+		"Linux FreeS/WAN 2.00 X.509-1.3.1 LDAP PLUTO_SENDS_VENDORID",
+		"FreeS/WAN 2.00 (X.509-1.3.1 + LDAP)")
+
+	/* NAT-Traversal */
+
+	DEC_MD5_VID(NATT_STENBERG_01, "draft-stenberg-ipsec-nat-traversal-01")
+	DEC_MD5_VID(NATT_STENBERG_02, "draft-stenberg-ipsec-nat-traversal-02")
+	DEC_MD5_VID(NATT_HUTTUNEN, "ESPThruNAT")
+	DEC_MD5_VID(NATT_HUTTUNEN_ESPINUDP, "draft-huttunen-ipsec-esp-in-udp-00.txt")
+	DEC_MD5_VID(NATT_IETF_00, "draft-ietf-ipsec-nat-t-ike-00")
+	DEC_MD5_VID(NATT_IETF_02, "draft-ietf-ipsec-nat-t-ike-02")
+	/* hash in draft-ietf-ipsec-nat-t-ike-02 contains '\n'... Accept both */
+	DEC_MD5_VID_D(NATT_IETF_02_N, "draft-ietf-ipsec-nat-t-ike-02\n", "draft-ietf-ipsec-nat-t-ike-02_n")
+	DEC_MD5_VID(NATT_IETF_03, "draft-ietf-ipsec-nat-t-ike-03")
+	DEC_MD5_VID(NATT_RFC, "Testing NAT-T RFC")
+
+	/* misc */
+	
+	{ VID_MISC_XAUTH, VID_KEEP, NULL, "XAUTH",
+		"\x09\x00\x26\x89\xdf\xd6\xb7\x12", 8 },
+
+	{ VID_MISC_DPD, VID_KEEP, NULL, "Dead Peer Detection",
+		"\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00",
+		16 },
+
+	/**
+	 * Netscreen:
+	 * 4865617274426561745f4e6f74696679386b0100  (HeartBeat_Notify + 386b0100)
+	 */
+	{ VID_MISC_HEARTBEAT_NOTIFY, VID_STRING | VID_SUBSTRING_DUMPHEXA,
+		"HeartBeat_Notify", "HeartBeat Notify", NULL, 0 },
+
+	DEC_MD5_VID(MISC_FRAGMENTATION, "FRAGMENTATION")
+
+	/* -- */
+	{ 0, 0, NULL, NULL, NULL, 0 }
+
+};
+
+static const char _hexdig[] = "0123456789abcdef";
+
+static int _vid_struct_init = 0;
+
+void init_vendorid(void)
+{
+	struct vid_struct *vid;
+	MD5_CTX ctx;
+	int i;
+
+	for (vid = _vid_tab; vid->id; vid++) {
+		if (vid->flags & VID_STRING) {
+			/** VendorID is a string **/
+			vid->vid = strdup(vid->data);
+			vid->vid_len = strlen(vid->data);
+		}
+		else if (vid->flags & VID_MD5HASH) {
+			/** VendorID is a string to hash with MD5 **/
+			char *vidm =  malloc(MD5_DIGEST_SIZE);
+			vid->vid = vidm;
+			if (vidm) {
+				MD5Init(&ctx);
+				MD5Update(&ctx, (unsigned char *)vid->data, strlen(vid->data));
+				MD5Final(vidm, &ctx);
+				vid->vid_len = MD5_DIGEST_SIZE;
+			}
+		}
+		else if (vid->flags & VID_FSWAN_HASH) {
+			/** FreeS/WAN 2.00+ specific hash **/
+#define FSWAN_VID_SIZE 12
+			unsigned char hash[MD5_DIGEST_SIZE];
+			char *vidm =  malloc(FSWAN_VID_SIZE);
+			vid->vid = vidm;
+			if (vidm) {
+				MD5Init(&ctx);
+				MD5Update(&ctx, (unsigned char *)vid->data, strlen(vid->data));
+				MD5Final(hash, &ctx);
+				vidm[0] = 'O';
+				vidm[1] = 'E';
+#if FSWAN_VID_SIZE - 2 <= MD5_DIGEST_SIZE
+				memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2);
+#else
+				memcpy(vidm + 2, hash, MD5_DIGEST_SIZE);
+				memset(vidm + 2 + MD5_DIGEST_SIZE, '\0',
+					FSWAN_VID_SIZE - 2 - MD5_DIGEST_SIZE);
+#endif
+				for (i = 2; i < FSWAN_VID_SIZE; i++) {
+					vidm[i] &= 0x7f;
+					vidm[i] |= 0x40;
+				}
+				vid->vid_len = FSWAN_VID_SIZE;
+			}
+		}
+
+		if (vid->descr == NULL) {
+			/** Find something to display **/
+			vid->descr = vid->data;
+		}
+#if 0
+		DBG_log("vendorid_init: %d [%s]",
+			vid->id,
+			vid->descr ? vid->descr : ""
+			);
+		if (vid->vid) DBG_dump("VID:", vid->vid, vid->vid_len);
+#endif
+	}
+	_vid_struct_init = 1;
+}
+
+static void handle_known_vendorid (struct msg_digest *md,
+	const char *vidstr, size_t len, struct vid_struct *vid)
+{
+	char vid_dump[128];
+	int vid_usefull = 0;
+	size_t i, j;
+
+	switch (vid->id) {
+#ifdef NAT_TRAVERSAL
+		/*
+		 * Use most recent supported NAT-Traversal method and ignore the
+		 * other ones (implementations will send all supported methods but
+		 * only one will be used)
+		 *
+		 * Note: most recent == higher id in vendor.h
+		 */
+		case VID_NATT_IETF_00:
+			if ((nat_traversal_enabled) && (!md->nat_traversal_vid)) {
+				md->nat_traversal_vid = vid->id;
+				vid_usefull = 1;
+			}
+			break;
+		case VID_NATT_IETF_02:
+		case VID_NATT_IETF_02_N:
+		case VID_NATT_IETF_03:
+		case VID_NATT_RFC:
+			if ((nat_traversal_support_port_floating) &&
+				(md->nat_traversal_vid < vid->id)) {
+				md->nat_traversal_vid = vid->id;
+				vid_usefull = 1;
+			}
+			break;
+#endif
+		default:
+			break;
+	}
+
+	if (vid->flags & VID_SUBSTRING_DUMPHEXA) {
+		/* Dump description + Hexa */
+		memset(vid_dump, 0, sizeof(vid_dump));
+		snprintf(vid_dump, sizeof(vid_dump), "%s ",
+			vid->descr ? vid->descr : "");
+		for (i=strlen(vid_dump), j=vid->vid_len;
+			(j<len) && (i<sizeof(vid_dump)-2);
+			i+=2, j++) {
+			vid_dump[i] = _hexdig[(vidstr[j] >> 4) & 0xF];
+			vid_dump[i+1] = _hexdig[vidstr[j] & 0xF];
+		}
+	}
+	else if (vid->flags & VID_SUBSTRING_DUMPASCII) {
+		/* Dump ASCII content */
+		memset(vid_dump, 0, sizeof(vid_dump));
+		for (i=0; (i<len) && (i<sizeof(vid_dump)-1); i++) {
+			vid_dump[i] = (isprint(vidstr[i])) ? vidstr[i] : '.';
+		}
+	}
+	else {
+		/* Dump description (descr) */
+		snprintf(vid_dump, sizeof(vid_dump), "%s",
+			vid->descr ? vid->descr : "");
+	}
+
+	loglog(RC_LOG_SERIOUS, "%s Vendor ID payload [%s]",
+		vid_usefull ? "received" : "ignoring", vid_dump);
+}
+
+void handle_vendorid (struct msg_digest *md, const char *vid, size_t len)
+{
+	struct vid_struct *pvid;
+
+	if (!_vid_struct_init) {
+		init_vendorid();
+	}
+
+	/*
+	 * Find known VendorID in _vid_tab
+	 */
+	for (pvid = _vid_tab; pvid->id; pvid++) {
+		if (pvid->vid && vid && pvid->vid_len && len) {
+			if (pvid->vid_len == len) {
+				if (memcmp(pvid->vid, vid, len)==0) {
+					handle_known_vendorid(md, vid, len, pvid);
+					return;
+				}
+			}
+			else if ((pvid->vid_len < len) && (pvid->flags & VID_SUBSTRING)) {
+				if (memcmp(pvid->vid, vid, pvid->vid_len)==0) {
+					handle_known_vendorid(md, vid, len, pvid);
+					return;
+				}
+			}
+		}
+	}
+
+	/*
+	 * Unknown VendorID. Log the beginning.
+	 */
+	{
+		char log_vid[2*MAX_LOG_VID_LEN+1];
+		size_t i;
+		memset(log_vid, 0, sizeof(log_vid));
+		for (i=0; (i<len) && (i<MAX_LOG_VID_LEN); i++) {
+			log_vid[2*i] = _hexdig[(vid[i] >> 4) & 0xF];
+			log_vid[2*i+1] = _hexdig[vid[i] & 0xF];
+		}
+		loglog(RC_LOG_SERIOUS, "ignoring Vendor ID payload [%s%s]",
+			log_vid, (len>MAX_LOG_VID_LEN) ? "..." : "");
+	}
+}
+
+/**
+ * Add a vendor id payload to the msg
+ */
+bool out_vendorid (u_int8_t np, pb_stream *outs, unsigned int vid)
+{
+	struct vid_struct *pvid;
+
+	if (!_vid_struct_init) {
+		init_vendorid();
+	}
+
+	for (pvid = _vid_tab; (pvid->id) && (pvid->id!=vid); pvid++);
+
+	if (pvid->id != vid) return STF_INTERNAL_ERROR; /* not found */
+	if (!pvid->vid) return STF_INTERNAL_ERROR; /* not initialized */
+
+	DBG(DBG_EMITTING,
+		DBG_log("out_vendorid(): sending [%s]", pvid->descr);
+	);
+
+	if (!out_modify_previous_np(ISAKMP_NEXT_VID, outs))
+		return FALSE;
+
+	return out_generic_raw(np, &isakmp_vendor_id_desc, outs,
+		(char *)pvid->vid, pvid->vid_len, "V_ID");
+}
+
diff -uNr freeswan-2.02.stock/programs/pluto/vendor.h freeswan-2.02/programs/pluto/vendor.h
--- freeswan-2.02.stock/programs/pluto/vendor.h	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/vendor.h	2003-10-11 09:16:16.000000000 -0400
@@ -0,0 +1,76 @@
+/* FreeS/WAN ISAKMP VendorID
+ * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: vendor.h,v 1.7 2003/01/13 17:57:15 mathieu Exp $
+ */
+
+#ifndef _VENDOR_H_
+#define _VENDOR_H_
+
+/* 1 - 100 : Implementation names */
+#define VID_OPENPGP                 1
+#define VID_KAME_RACOON             2
+#define VID_MS_NT5                  3
+#define VID_SSH_SENTINEL            4
+#define VID_SSH_SENTINEL_1_1        5
+#define VID_SSH_SENTINEL_1_2        6
+#define VID_SSH_SENTINEL_1_3        7
+#define VID_SSH_IPSEC_1_1_0         8
+#define VID_SSH_IPSEC_1_1_1         9
+#define VID_SSH_IPSEC_1_1_2         10
+#define VID_SSH_IPSEC_1_2_1         11
+#define VID_SSH_IPSEC_1_2_2         12
+#define VID_SSH_IPSEC_2_0_0         13
+#define VID_SSH_IPSEC_2_1_0         14
+#define VID_SSH_IPSEC_2_1_1         15
+#define VID_SSH_IPSEC_2_1_2         16
+#define VID_SSH_IPSEC_3_0_0         17
+#define VID_SSH_IPSEC_3_0_1         18
+#define VID_SSH_IPSEC_4_0_0         19
+#define VID_SSH_IPSEC_4_0_1         20
+#define VID_SSH_IPSEC_4_1_0         21
+#define VID_SSH_IPSEC_4_2_0         22
+#define VID_CISCO_UNITY             23
+#define VID_SSH_SENTINEL_1_4        24
+#define VID_SSH_SENTINEL_1_4_1      25
+#define VID_TIMESTEP                26
+#define VID_FSWAN_2_00_VID                  27
+#define VID_FSWAN_2_00_X509_1_3_1_VID       28
+#define VID_FSWAN_2_00_X509_1_3_1_LDAP_VID  29
+
+/* 101 - 200 : NAT-Traversal */
+#define VID_NATT_STENBERG_01        101
+#define VID_NATT_STENBERG_02        102
+#define VID_NATT_HUTTUNEN           103
+#define VID_NATT_HUTTUNEN_ESPINUDP  104
+#define VID_NATT_IETF_00            105
+#define VID_NATT_IETF_02_N          106
+#define VID_NATT_IETF_02            107
+#define VID_NATT_IETF_03            108
+#define VID_NATT_RFC                109
+
+/* 201 - 300 : Misc */
+#define VID_MISC_XAUTH              201
+#define VID_MISC_DPD                202
+#define VID_MISC_HEARTBEAT_NOTIFY   203
+#define VID_MISC_FRAGMENTATION      204
+
+void init_vendorid(void);
+
+struct msg_digest;
+void handle_vendorid (struct msg_digest *md, const char *vid, size_t len);
+
+bool out_vendorid (u_int8_t np, pb_stream *outs, unsigned int vid);
+
+#endif /* _VENDOR_H_ */
+
diff -uNr freeswan-2.02.stock/programs/pluto/virtual.c freeswan-2.02/programs/pluto/virtual.c
--- freeswan-2.02.stock/programs/pluto/virtual.c	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/virtual.c	2003-10-11 17:58:39.000000000 -0400
@@ -0,0 +1,325 @@
+/* FreeS/WAN Virtual IP Management
+ * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: virtual.c,v 1.3 2002/09/24 18:13:26 mathieu Exp $
+ */
+
+#ifdef VIRTUAL_IP
+
+#include <freeswan.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "certs.h"
+#include "smartcard.h"
+#include "connections.h"
+#include "whack.h"
+#include "virtual.h"
+
+#define F_VIRTUAL_NO          1
+#define F_VIRTUAL_DHCP        2
+#define F_VIRTUAL_IKE_CONFIG  4
+#define F_VIRTUAL_PRIVATE     8
+#define F_VIRTUAL_ALL         16
+#define F_VIRTUAL_HOST        32
+
+struct virtual_t {
+    unsigned short flags;
+    unsigned short n_net;
+    ip_subnet net[0];
+};
+
+static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL;
+static unsigned short private_net_ok_len=0, private_net_ko_len=0;
+
+/**
+ * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy
+ * or %v4:!x.x.x.x/y if dstko not NULL
+ */
+static bool
+_read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko,
+    bool *isok)
+{
+    bool ok;
+    int af;
+
+    if ((len > 4) && (strncmp(src, "%v4:", 4)==0)) {
+	af = AF_INET;
+    }
+    else if ((len > 4) && (strncmp(src, "%v6:", 4)==0)) {
+	af = AF_INET6;
+    }
+    else {
+	return FALSE;
+    }
+
+    ok = (src[4] == '!') ? FALSE : TRUE;
+    src += ok ? 4 : 5;
+    len -= ok ? 4 : 5;
+
+    if (!len) return FALSE;
+    if ((!ok) && (!dstko)) return FALSE;
+
+    passert ( ((ok)?(dst):(dstko))!=NULL );
+
+    if (ttosubnet(src, len, af, ((ok)?(dst):(dstko)))) {
+	return FALSE;
+    }
+    if (isok) *isok = ok;
+    return TRUE;
+}
+
+void
+init_virtual_ip(const char *private_list)
+{
+    const char *next, *str=private_list;
+    unsigned short ign = 0, i_ok, i_ko;
+    ip_subnet sub;
+    bool ok;
+
+    /** Count **/
+    private_net_ok_len=0;
+    private_net_ko_len=0;
+    while (str) {
+	next = strchr(str,',');
+	if (!next) next = str + strlen(str);
+	if (_read_subnet(str, next-str, &sub, &sub, &ok)) {
+	    if (ok)
+		private_net_ok_len++;
+	    else
+		private_net_ko_len++;
+	}
+	else {
+	    ign++;
+	}
+	str = *next ? next+1 : NULL;
+    }
+
+    if (!ign) {
+	/** Allocate **/
+	if (private_net_ok_len) {
+	    private_net_ok = (ip_subnet *)alloc_bytes(
+		(private_net_ok_len*sizeof(ip_subnet)),
+		"private_net_ok subnets");
+	}
+	if (private_net_ko_len) {
+	    private_net_ko = (ip_subnet *)alloc_bytes(
+		(private_net_ko_len*sizeof(ip_subnet)),
+		"private_net_ko subnets");
+	}
+	if ((private_net_ok_len && !private_net_ok) ||
+	    (private_net_ko_len && !private_net_ko)) {
+	    loglog(RC_LOG_SERIOUS,
+		"can't alloc in init_virtual_ip");
+	    pfreeany(private_net_ok);
+	    private_net_ok = NULL;
+	    pfreeany(private_net_ko);
+	    private_net_ko = NULL;
+	}
+	else {
+	    /** Fill **/
+	    str = private_list;
+	    i_ok = 0;
+	    i_ko = 0;
+	    while (str) {
+		next = strchr(str,',');
+		if (!next) next = str + strlen(str);
+		if (_read_subnet(str, next-str,
+		   &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok)) {
+		    if (ok)
+			i_ok++;
+		    else
+			i_ko++;
+		}
+		str = *next ? next+1 : NULL;
+	    }
+	}
+    }
+    else {
+	loglog(RC_LOG_SERIOUS,
+	    "%d bad entries in virtual_private - none loaded", ign);
+    }
+}
+
+/**
+ * virtual string must be :
+ * {vhost,vnet}:[%method]*
+ *
+ * vhost = accept only a host (/32)
+ * vnet  = accept any network
+ *
+ * %no   = no virtual IP (accept public IP)
+ * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP  [not implemented]
+ * %ike  = accept affected IKE Config Mode IP         [not implemented]
+ * %priv = accept system-wide private net list
+ * %v4:x = accept ipv4 in list 'x'
+ * %v6:x = accept ipv6 in list 'x'
+ * %all  = accept all ips                             [only for testing]
+ *
+ * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24
+ */
+struct virtual_t
+*create_virtual(const struct connection *c, const char *string)
+{
+    unsigned short flags=0, n_net=0, i;
+    const char *str = string, *next, *first_net=NULL;
+    ip_subnet sub;
+    struct virtual_t *v;
+
+    if ((!string) || (string[0]=='\0')) return NULL;
+
+    if ((strlen(string)>=6) && (strncmp(string,"vhost:",6)==0)) {
+	flags |= F_VIRTUAL_HOST;
+	str += 6;
+    }
+    else if ((strlen(string)>=5) && (strncmp(string,"vnet:",5)==0)) {
+	str += 5;
+    }
+    else {
+	goto fail;
+    }
+
+    /**
+     * Parse string : fill flags & count subnets
+     */
+    while ((str) && (*str)) {
+	next = strchr(str,',');
+	if (!next) next = str + strlen(str);
+	if ((next-str == 3) && (strncmp(str, "%no", 3)==0)) {
+	    flags |= F_VIRTUAL_NO;
+	}
+#if 0
+	else if ((next-str == 4) && (strncmp(str, "%ike", 4)==0)) {
+	    flags |= F_VIRTUAL_IKE_CONFIG;
+	}
+	else if ((next-str == 5) && (strncmp(str, "%dhcp", 5)==0)) {
+	    flags |= F_VIRTUAL_DHCP;
+	}
+#endif
+	else if ((next-str == 5) && (strncmp(str, "%priv", 5)==0)) {
+	    flags |= F_VIRTUAL_PRIVATE;
+	}
+	else if ((next-str == 4) && (strncmp(str, "%all", 4)==0)) {
+	    flags |= F_VIRTUAL_ALL;
+	}
+	else if (_read_subnet(str, next-str, &sub, NULL, NULL)) {
+	    n_net++;
+	    if (!first_net) first_net = str;
+	}
+	else {
+	    goto fail;
+	}
+	str = *next ? next+1 : NULL;
+    }
+
+    v = (struct virtual_t *)alloc_bytes(
+	sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)),
+	"virtual description");
+    if (!v) goto fail;
+
+    v->flags = flags;
+    v->n_net = n_net;
+    if (n_net && first_net) {
+	/**
+	 * Save subnets in newly allocated struct
+	 */
+	for (str=first_net, i=0; (str) && (*str); ) {
+	    next = strchr(str,',');
+	    if (!next) next = str + strlen(str);
+	    if (_read_subnet(str, next-str, &(v->net[i]), NULL, NULL))
+		i++;
+	    str = *next ? next+1 : NULL;
+	}
+    }
+
+    return v;
+
+fail:
+    plog("invalid virtual string [%s] - "
+	"virtual selection disabled for connection '%s'", string, c->name);
+    return NULL;
+}
+
+bool
+is_virtual_end(const struct end *that)
+{
+    return ((that->virt)?TRUE:FALSE);
+}
+
+bool
+is_virtual_connection(const struct connection *c)
+{
+    return ((c->spd.that.virt)?TRUE:FALSE);
+}
+
+static bool
+net_in_list(const ip_subnet *peer_net, const ip_subnet *list,
+    unsigned short len)
+{
+    unsigned short i;
+    if (!list || !len) return FALSE;
+    for (i=0; i<len; i++) {
+	if (subnetinsubnet(peer_net, &(list[i])))
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+bool
+is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net,
+	const ip_address *his_addr)
+{
+    if (!c->spd.that.virt) return FALSE;
+
+    if (c->spd.that.virt->flags & F_VIRTUAL_HOST) {
+	if (!subnetishost(peer_net))
+	    return FALSE;
+    }
+
+    if (c->spd.that.virt->flags & F_VIRTUAL_NO) {
+	if (subnetishost(peer_net) &&
+	    addrinsubnet(his_addr, peer_net))
+	    return TRUE;
+    }
+
+    if (c->spd.that.virt->flags & F_VIRTUAL_PRIVATE) {
+	if (net_in_list(peer_net, private_net_ok, private_net_ok_len) &&
+	    !net_in_list(peer_net, private_net_ko, private_net_ko_len))
+	    return TRUE;
+    }
+
+    if (c->spd.that.virt->n_net) {
+	if (net_in_list(peer_net, c->spd.that.virt->net, c->spd.that.virt->n_net))
+	    return TRUE;
+    }
+
+    if (c->spd.that.virt->flags & F_VIRTUAL_ALL) {
+	/** %all must only be used for testing - log it **/
+	loglog(RC_LOG_SERIOUS, "Warning - "
+	    "v%s:%%all must only be used for testing",
+	    (c->spd.that.virt->flags & F_VIRTUAL_HOST) ? "host" : "net");
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+#endif
+
diff -uNr freeswan-2.02.stock/programs/pluto/virtual.h freeswan-2.02/programs/pluto/virtual.h
--- freeswan-2.02.stock/programs/pluto/virtual.h	1969-12-31 19:00:00.000000000 -0500
+++ freeswan-2.02/programs/pluto/virtual.h	2003-10-11 09:16:16.000000000 -0400
@@ -0,0 +1,31 @@
+/* FreeS/WAN Virtual IP Management
+ * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: virtual.h,v 1.3 2002/09/24 18:13:26 mathieu Exp $
+ */
+
+#ifndef _VIRTUAL_IP_H
+#define _VIRTUAL_IP_H
+
+extern void init_virtual_ip(const char *private_list);
+
+extern struct virtual_t *create_virtual(const struct connection *c,
+    const char *string);
+
+extern bool is_virtual_end(const struct end *that);
+extern bool is_virtual_connection(const struct connection *c);
+extern bool is_virtual_net_allowed(const struct connection *c,
+    const ip_subnet *peer_net, const ip_address *his_addr);
+
+#endif /* _VIRTUAL_IP_H */
+
diff -uNr freeswan-2.02.stock/programs/pluto/whack.c freeswan-2.02/programs/pluto/whack.c
--- freeswan-2.02.stock/programs/pluto/whack.c	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/whack.c	2003-10-11 09:27:13.000000000 -0400
@@ -1028,8 +1028,19 @@
 	    if (end_seen & LELEM(END_CLIENTWITHIN - END_FIRST))
 		diag("--client conflicts with --clientwithin");
 	    tunnel_af_used_by = long_opts[long_index].name;
+#ifdef VIRTUAL_IP
+	    if ( ((strlen(optarg)>=6) && (strncmp(optarg,"vhost:",6)==0)) ||
+		((strlen(optarg)>=5) && (strncmp(optarg,"vnet:",5)==0)) ) {
+		msg.right.virt = optarg;
+	    }
+	    else {
+		diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
+		msg.right.has_client = TRUE;
+	    }
+#else
 	    diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg);
 	    msg.right.has_client = TRUE;
+#endif
 	    msg.policy |= POLICY_TUNNEL;	/* client => tunnel */
 	    continue;
 
@@ -1338,10 +1349,16 @@
     || !pack_str(&msg.left.cert)	/* string  3 */
     || !pack_str(&msg.left.ca)		/* string  4 */
     || !pack_str(&msg.left.updown)	/* string  5 */
+#ifdef VIRTUAL_IP
+    || !pack_str(&msg.left.virt)
+#endif
     || !pack_str(&msg.right.id)		/* string  6 */
     || !pack_str(&msg.right.cert)	/* string  7 */
     || !pack_str(&msg.right.ca)		/* string  8 */
     || !pack_str(&msg.right.updown)	/* string  9 */
+#ifdef VIRTUAL_IP
+    || !pack_str(&msg.right.virt)
+#endif
     || !pack_str(&msg.keyid)		/* string 10 */
     || !pack_str(&msg.myid)		/* string 11 */
     || str_roof - next_str < (ptrdiff_t)msg.keyval.len)    /* chunk (sort of string 5) */
diff -uNr freeswan-2.02.stock/programs/pluto/whack.h freeswan-2.02/programs/pluto/whack.h
--- freeswan-2.02.stock/programs/pluto/whack.h	2003-10-11 18:01:19.000000000 -0400
+++ freeswan-2.02/programs/pluto/whack.h	2003-10-11 09:16:16.000000000 -0400
@@ -55,6 +55,9 @@
     u_int16_t host_port;	/* host order */
     u_int16_t port;		/* host order */
     u_int8_t protocol;
+#ifdef VIRTUAL_IP
+    char *virt;
+#endif
  };
 
 struct whack_message {
