--- vpnc-0.2-rm+zomb.1.orig/debian/control
+++ vpnc-0.2-rm+zomb.1/debian/control
@@ -0,0 +1,20 @@
+Source: vpnc
+Section: net
+Priority: extra
+Maintainer: Eduard Bloch <blade@debian.org>
+Build-Depends: debhelper (>= 4.0.0), libgcrypt7-dev, dpatch
+Standards-Version: 3.6.1
+
+Package: vpnc
+Architecture: any
+Depends: iproute, ${shlibs:Depends}, ${misc:Depends}
+Suggests: resolvconf
+Description: Cisco-compatible VPN client
+ vpnc is a VPN client compatible with cisco3000 VPN Concentrator (also
+ known as Cisco's EasyVPN equipment). vpnc runs entirely in userspace
+ and does not require kernel modules except of the tun driver to
+ communicate with the network layer.
+ .
+ It supports most of the features needed to establish connection to the
+ VPN concentrator: MD5 and SHA1 hashes, 3DES and AES ciphers, PFS and
+ various IKE DH group settings.
--- vpnc-0.2-rm+zomb.1.orig/debian/vpnc.examples
+++ vpnc-0.2-rm+zomb.1/debian/vpnc.examples
@@ -0,0 +1 @@
+vpnc.conf
--- vpnc-0.2-rm+zomb.1.orig/debian/compat
+++ vpnc-0.2-rm+zomb.1/debian/compat
@@ -0,0 +1 @@
+4
--- vpnc-0.2-rm+zomb.1.orig/debian/vpnc.dirs
+++ vpnc-0.2-rm+zomb.1/debian/vpnc.dirs
@@ -0,0 +1,2 @@
+usr/sbin
+var/run/vpnc
--- vpnc-0.2-rm+zomb.1.orig/debian/changelog
+++ vpnc-0.2-rm+zomb.1/debian/changelog
@@ -0,0 +1,125 @@
+vpnc (0.2-rm+zomb.1-6.backports.org.1) unstable; urgency=low
+
+  * recompiled for http://www.backports.org/
+
+ -- Norbert Tretkowski <tretkowski@inittab.de>  Thu, 24 Jun 2004 22:15:09 +0200
+
+vpnc (0.2-rm+zomb.1-7) unstable; urgency=low
+
+  * pre-release upstream update
+    + keeping the same syslog facility after fork (closes: #251228)
+    + insecurity warnings in README.Debian and vpnc.8 (closes: #251935)
+    + general PIX support was added in the previous release (closes: #220233)
+  * changes to use dpatch
+  * upstream TODO file re-added (closes: #254034)
+  * patch from Wolfgang Ratzka to add direct gateway route even if Target
+    networks is set (closes: #253051)
+
+ -- Eduard Bloch <blade@debian.org>  Wed, 26 May 2004 16:57:52 +0200
+
+vpnc (0.2-rm+zomb.1-6) unstable; urgency=low
+
+  * Made checks for tun_init be less precise to match on kernel 2.4
+
+ -- Eduard Bloch <blade@debian.org>  Wed, 26 May 2004 16:16:16 +0200
+
+vpnc (0.2-rm+zomb.1-5) unstable; urgency=low
+
+  * Fix of the fix of the last tree RC bugs, also use the right command [tm]
+    to display the help text, thanks to Michael Farmbauer (closes: #250839)
+  * More alternative checks for the tun driver presence
+
+ -- Eduard Bloch <blade@debian.org>  Mon, 24 May 2004 18:12:05 +0200
+
+vpnc (0.2-rm+zomb.1-4) unstable; urgency=low
+
+  * Moved the config file argument into the quotes when specifying the
+    configuration script argument (closes: #250695, #250673, #240766)
+  * installing example config file into /etc/vpnc/ (closes: #246714)
+  * checking $1 before shift to not confuse dash
+  * made vpnc-connect be quiet if CONFIG_TUN=y was found in the guessed kernel
+    config file (closes: #250237)
+
+ -- Eduard Bloch <blade@debian.org>  Mon, 17 May 2004 17:55:22 +0200
+
+vpnc (0.2-rm+zomb.1-3) unstable; urgency=low
+
+  * the third-time-lucky revision
+  * removed surrounding quotes in the DNS server list
+
+ -- Eduard Bloch <blade@debian.org>  Sat, 15 May 2004 21:31:15 +0200
+
+vpnc (0.2-rm+zomb.1-2) unstable; urgency=low
+
+  * vpnc.c: Only warn about additional ("unknown") config directives in 
+    debug mode (as it was done in -pre8 before)
+  * vpnc-connect: adding explicite routes to VPNed DNS servers if needed
+  * avoiding multi-line if-statements, report to break with some shell
+
+ -- Eduard Bloch <blade@debian.org>  Fri, 14 May 2004 15:18:52 +0200
+
+vpnc (0.2-rm+zomb.1-1) unstable; urgency=low
+
+  * New upstream release
+  * resolvconf integration to implement DNS data update mechanism
+
+ -- Eduard Bloch <blade@debian.org>  Fri, 14 May 2004 09:04:26 +0200
+
+vpnc (0.2-rm+zomb-pre8-1) unstable; urgency=low
+
+  * New upstream release
+  * added Interface name to the manpage example and a default value to the
+    vpnc-connect script
+
+ -- Eduard Bloch <blade@debian.org>  Sun, 25 Apr 2004 10:56:01 +0200
+
+vpnc (0.2-rm+zomb-pre7-4) unstable; urgency=low
+
+  * Multiple config management patch by Tobias Oetiker <oetiker@ee.ethz.ch>
+  * Manpage updates based on the patch above
+  * Fixed the route check on the defaultroute restoring (thanks to Thomas
+    Deselaers, closes: #230806)
+
+ -- Eduard Bloch <blade@debian.org>  Thu, 29 Jan 2004 11:06:00 +0100
+
+vpnc (0.2-rm+zomb-pre7-3) unstable; urgency=low
+
+  * Does not clobber the default route if custom routes have been defined
+    (successor of the #225776 fix), thanks to Steven Ihde (closes: #230201)
+
+ -- Eduard Bloch <blade@debian.org>  Wed, 28 Jan 2004 20:23:10 +0100
+
+vpnc (0.2-rm+zomb-pre7-2) unstable; urgency=low
+
+  * vpnc-connect: allow customizable target routes in vpnc.conf 
+    (closes: #225776)
+  * vpnc.c: don't bother about unknown options unless --debug is used
+  * merged relevant parts of the FreeBSD manpage Debian into out Linux
+    version, replaced hyphens with minus signs (\-) and stopped using the SGML
+    template. It just sucked.
+
+ -- Eduard Bloch <blade@debian.org>  Thu, 18 Dec 2003 21:14:11 +0100
+
+vpnc (0.2-rm+zomb-pre7-1) unstable; urgency=low
+
+  * New upstream release
+    + vpnc-connect filters weird ip output (closes: #220495)
+  * Builds with the new libgcrypt generation, Build-Deps adjusted
+  * Typo in description fixed (closes: #220172)
+
+ -- Eduard Bloch <blade@debian.org>  Thu, 18 Dec 2003 20:28:02 +0100
+
+vpnc (0.2-rm+zomb-pre5-2) unstable; urgency=low
+
+  * Fixed the test condition when looking for the tun device node
+  * vpnc.c: fixed --local-port description
+  * provisoric manpage written
+
+ -- Eduard Bloch <blade@debian.org>  Mon,  3 Nov 2003 22:41:04 +0100
+
+vpnc (0.2-rm+zomb-pre5-1) unstable; urgency=low
+
+  * Initial Release (closes: #217838)
+
+ -- Eduard Bloch <blade@debian.org>  Thu, 30 Oct 2003 07:08:26 +0100
+
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/02_vpnc-disconnect.dpatch
+++ vpnc-0.2-rm+zomb.1/debian/patches/02_vpnc-disconnect.dpatch
@@ -0,0 +1,55 @@
+#! /bin/sh -e
+## 02_vpnc-disconnect.dpatch by Eduard Bloch <blade@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+if [ $# -lt 1 ]; then
+    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+    exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
+
+case "$1" in
+    -patch) patch -p1 ${patch_opts} < $0;;
+    -unpatch) patch -R -p1 ${patch_opts} < $0;;
+    *)
+        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+        exit 1;;
+esac
+
+exit 0
+
+@DPATCH@
+diff -urNad /home/inet/debian/dev/vpnc/vpnc-disconnect vpnc/vpnc-disconnect
+--- /home/inet/debian/dev/vpnc/vpnc-disconnect	2004-06-17 16:04:49.000000000 +0200
++++ vpnc/vpnc-disconnect	2004-06-17 16:09:19.000000000 +0200
+@@ -3,6 +3,7 @@
+ defr=/var/run/vpnc/defaultroute
+ gateway=/var/run/vpnc/gateway
+ pid=/var/run/vpnc/pid
++dnsdev=/var/run/vpnc/dev
+ 
+ if [ $# -ne 0 ]; then
+ 	echo "Usage: $0" 1>&2
+@@ -30,10 +31,17 @@
+ if [ -s "$defr" ]; then
+ 	ip route del default > /dev/null 2>&1
+ 	ip route add $(cat "$defr")
+-	test -r "$gateway" && ip route del $(cat "$gateway")
++	test -s "$gateway" && ip route del $(cat "$gateway")
++	ip route flush cache
++elif [ -s "$gateway" ]; then
++        ip route del $(cat "$gateway")
+ 	ip route flush cache
+ fi
+ 
++if [ -s "$dnsdev" ] && [ -e /sbin/resolvconf ] ; then
++   /sbin/resolvconf -d `cat $dnsdev`
++fi
++
+ rm -f -- "$defr" "$pid" "$gateway"
+ 
+ exit 0
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/03_vpnc.8.dpatch
+++ vpnc-0.2-rm+zomb.1/debian/patches/03_vpnc.8.dpatch
@@ -0,0 +1,80 @@
+#! /bin/sh -e
+## 03_vpnc.8.dpatch by Eduard Bloch <blade@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+if [ $# -lt 1 ]; then
+    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+    exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
+
+case "$1" in
+    -patch) patch -p1 ${patch_opts} < $0;;
+    -unpatch) patch -R -p1 ${patch_opts} < $0;;
+    *)
+        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+        exit 1;;
+esac
+
+exit 0
+
+@DPATCH@
+diff -urNad /home/inet/debian/dev/vpnc/vpnc.8 vpnc/vpnc.8
+--- /home/inet/debian/dev/vpnc/vpnc.8	2004-06-17 16:00:28.000000000 +0200
++++ vpnc/vpnc.8	2004-06-17 16:11:21.000000000 +0200
+@@ -47,6 +47,10 @@
+ on BSD. The created connection is presented as a tunneling network
+ device to the local system.
+ .PP
++OBLICATORY WARNING: the most used configuration (XAUTH authentication)
++is insecure by design, be aware of this fact when you use vpnc to
++exchange sensitive data like passwords!
++.PP
+ The vpnc daemon by it self does not set any routes, the user (or
+ the connect script, see below) has to do it on its own, e.g. for a full
+ tunnel with IP routing under Linux. Further, the user must care about
+@@ -213,6 +217,40 @@
+ Advanced features like manual setting of multiple target routes is
+ documented in the example files of the vpnc package.
+ 
++.SH ADVANCED USAGE
++The vpnc-connect stript shipped with Debian has some additional
++features:
++.IP "Custom route setting"
++By default, the default route is deleted after connection and replaced
++with the new one (going trough the VPN tunnel device). However, some
++people wish to limit the target address range to few IP ranges.
++This can be done using the config directive
++.B Target networks
++in the config file. For example:
++.RS
++.PD 0
++Target networks 123.234.210.0/24 10.1.0.0/16
++.PD
++.RE
++.IP "Multiple config profiles management"
++You can have multiple config files and select one on connection by
++specifying a short profile name instead of a config file path. In this
++case, the file
++.I /etc/vpnc/PROFILE.conf
++is used as config file (where PROFILE is the short profile name).
++.IP "/etc/resolv.conf update"
++If the package 
++.B resolvconf
++is installed and the VPN gateway sends some DNS server data, the
++script will use resolution to integrate the received data into
++.I /etc/resolv.conf.
++To disable this behaviour, set the config directive
++.I DNSUpdate
++to the
++.I "no"
++value.
++
++
+ .SH TODO
+ .PD 0
+ Re-keying is not implemented yet (default rekey-intervall is 8 hours).
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/05_vpnc.conf.dpatch
+++ vpnc-0.2-rm+zomb.1/debian/patches/05_vpnc.conf.dpatch
@@ -0,0 +1,49 @@
+#! /bin/sh -e
+## 05_vpnc.conf.dpatch by Eduard Bloch <blade@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+if [ $# -lt 1 ]; then
+    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+    exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
+
+case "$1" in
+    -patch) patch -p1 ${patch_opts} < $0;;
+    -unpatch) patch -R -p1 ${patch_opts} < $0;;
+    *)
+        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+        exit 1;;
+esac
+
+exit 0
+
+@DPATCH@
+diff -urNad /home/inet/debian/dev/vpnc/vpnc.conf vpnc/vpnc.conf
+--- /home/inet/debian/dev/vpnc/vpnc.conf	2004-06-17 16:00:28.000000000 +0200
++++ vpnc/vpnc.conf	2004-06-17 16:15:16.000000000 +0200
+@@ -1,4 +1,17 @@
+-IPSec gateway 131.246.118.240
+-IPSec ID unikl
+-IPSec secret unikl
++IPSec gateway 121.146.218.140
++IPSec ID mygroup
++IPSec secret mygrouppwd
+ Xauth username abcdef
++
++# OPTIONAL
++# ========
++
++#Interface name vpnlink
++
++# Varios options not undestood by vpnc itself but by some other scripts
++#
++# Target networks 123.234.210.0/24 10.1.0.0/16
++# If Target networks is defined here, the default route is not replaced!
++
++# Don't update resolv.conf though resolvconf is installed
++# DNSUpdate no
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/01_preview_2004-06-17.dpatch
+++ vpnc-0.2-rm+zomb.1/debian/patches/01_preview_2004-06-17.dpatch
@@ -0,0 +1,9810 @@
+#! /bin/sh -e
+## 02_vpnc-disconnect.dpatch by Eduard Bloch <blade@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+if [ $# -lt 1 ]; then
+    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+    exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
+
+case "$1" in
+    -patch) patch -p1 ${patch_opts} < $0;;
+    -unpatch) patch -R -p1 ${patch_opts} < $0;;
+    *)
+        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+        exit 1;;
+esac
+
+exit 0
+
+@DPATCH@
+diff -Nurd vpnc-0.2-rm+zomb.1/config.c new/config.c
+--- vpnc-0.2-rm+zomb.1/config.c	1970-01-01 01:00:00.000000000 +0100
++++ new/config.c	2004-06-03 09:56:39.000000000 +0200
+@@ -0,0 +1,549 @@
++/* IPSec VPN client compatible with Cisco equipment.
++   Copyright (C) 2004 Maurice Massar
++
++   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.
++   
++   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.
++   
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#define _GNU_SOURCE
++
++#include <inttypes.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/utsname.h>
++
++#include "sysdep.h"
++#include "config.h"
++#include "vpnc.h"
++
++/*
++#include <assert.h>
++#include <sys/fcntl.h>
++#include <time.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <netdb.h>
++#include <arpa/inet.h>
++#include <poll.h>
++#include <net/if.h>
++#include <sys/ioctl.h>
++
++#include <gcrypt.h>
++
++#include "isakmp-pkt.h"
++#include "math_group.h"
++#include "dh.h"
++*/
++
++const char *config[LAST_CONFIG];
++
++int opt_debug = 0;
++int opt_nd;
++int opt_1des;
++
++void hex_dump(const char *str, const void *data, ssize_t len)
++{
++	size_t i;
++	const uint8_t *p = data;
++
++	if (opt_debug < 3)
++		return;
++
++	switch (len) {
++	case UINT8:
++		printf("%s: %02x\n", str, *(uint8_t *)p);
++		return;
++	case UINT16:
++		printf("%s: %04x\n", str, *(uint16_t *)p);
++		return;
++	case UINT32:
++		printf("%s: %08x\n", str, *(uint32_t *)p);
++		return;
++	}
++
++	printf("%s:%c", str, (len <= 32) ? ' ' : '\n');
++	for (i = 0; i < (size_t)len; i++) {
++		if (i && !(i % 32))
++			printf("\n");
++		else if (i && !(i % 4))
++			printf(" ");
++		printf("%02x", p[i]);
++	}
++	printf("\n");
++}
++
++static const char *config_def_description(void)
++{
++	return "default value for this option";
++}
++
++static const char *config_def_ike_dh(void)
++{
++	return "dh2";
++}
++
++static const char *config_def_pfs(void)
++{
++	return "server";
++}
++
++static const char *config_def_local_port(void)
++{
++	return "500";
++}
++
++static const char *config_def_app_version(void)
++{
++	struct utsname uts;
++	char *version;
++
++	uname(&uts);
++	asprintf(&version, "Cisco Systems VPN Client %s:%s", VERSION, uts.sysname);
++	return version;
++}
++
++static const struct config_names_s {
++	enum config_enum nm;
++	const int needsArgument;
++	const int lvl;
++	const char *option;
++	const char *name;
++	const char *type;
++	const char *desc;
++	const char *(*get_def) (void);
++} config_names[] = {
++	/* Note: broken config file parser does NOT support option
++	 * names where one is a prefix of another option. Needs just a bit work to
++	 * fix the parser to care about ' ' or '\t' after the wanted
++	 * option... */
++	{
++		CONFIG_NONE, 0, 0,
++		"commandline option,",
++		"configfile variable, ",
++		"argument type",
++		"description",
++		config_def_description
++	}, {
++		CONFIG_IPSEC_GATEWAY, 1, 0,
++		"--gateway",
++		"IPSec gateway ",
++		"<ip/hostname>",
++		"IP/name of your IPSec gateway",
++		NULL
++	}, {
++		CONFIG_IPSEC_ID, 1, 0,
++		"--id",
++		"IPSec ID ",
++		"<ASCII string>",
++		"your group name",
++		NULL
++	}, {
++		CONFIG_IPSEC_SECRET, 1, 0,
++		NULL,
++		"IPSec secret ",
++		"<ASCII string>",
++		"your group password (cleartext, no support for obfuscated strings)",
++		NULL
++	}, {
++		CONFIG_XAUTH_USERNAME, 1, 0,
++		"--username",
++		"Xauth username ",
++		"<ASCII string>",
++		"your username",
++		NULL
++	}, {
++		CONFIG_XAUTH_PASSWORD, 1, 0,
++		NULL,
++		"Xauth password ",
++		"<ASCII string>",
++		"your password (cleartext, no support for obfuscated strings)",
++		NULL
++	}, {
++		CONFIG_DOMAIN, 1, 1,
++		"--domain",
++		"Domain ",
++		"<ASCII string>",
++		"(NT-) Domain name for authentication",
++		NULL
++	}, {
++		CONFIG_XAUTH_INTERACTIVE, 0, 1,
++		"--xauth-inter",
++		"Xauth interactive",
++		NULL,
++		"enable interactive extended authentication (for challange response auth)",
++		NULL
++	}, {
++		CONFIG_CONFIG_SCRIPT, 1, 1,
++		"--script",
++		"Config Script ",
++		"<command>",
++		"command is executed using system() to configure the interface,\n"
++		"routing and so on. Device name, IP, etc. are passed using enviroment\n"
++		"variables, see README. This script is executed right after ISAKMP is\n"
++		"done, but befor tunneling is enabled.\n",
++		sysdep_config_script
++	}, {
++		CONFIG_IKE_DH, 1, 1,
++		"--dh",
++		"IKE DH Group ",
++		"<dh1/dh2/dh5>",
++		"name of the IKE DH Group",
++		config_def_ike_dh
++	}, {
++		CONFIG_IPSEC_PFS, 1, 1,
++		"--pfs",
++		"Perfect Forward Secrecy ",
++		"<nopfs/dh1/dh2/dh5/server>",
++		"Diffie-Hellman group to use for PFS",
++		config_def_pfs
++	}, {
++		CONFIG_ENABLE_1DES, 0, 1,
++		"--enable-1des",
++		"Enable Single DES",
++		NULL,
++		"enables weak single DES encryption",
++		NULL
++	}, {
++		CONFIG_VERSION, 1, 1,
++		"--application-version",
++		"Application version ",
++		"<ASCII string>",
++		"Application Version to report",
++		config_def_app_version
++	}, {
++		CONFIG_IF_NAME, 1, 1,
++		"--ifname",
++		"Interface name ",
++		"<ASCII string>",
++		"visible name of the TUN interface",
++		NULL
++	}, {
++		CONFIG_DEBUG, 1, 1,
++		"--debug",
++		"Debug ",
++		"<0/1/2/3/99>",
++		"Show verbose debug messages",
++		NULL
++	}, {
++		CONFIG_ND, 0, 1,
++		"--no-detach",
++		"No Detach",
++		NULL,
++		"Don't detach from the console after login",
++		NULL
++	}, {
++		CONFIG_PID_FILE, 1, 1,
++		"--pid-file",
++		"Pidfile ",
++		"<filename>",
++		"store the pid of background process in <filename>",
++		NULL
++	}, {
++		CONFIG_LOCAL_PORT, 1, 1,
++		"--local-port",
++		"Local Port ",
++		"<0-65535>",
++		"local ISAKMP port number to use (0 == use random port)",
++		config_def_local_port
++	}, {
++		CONFIG_NON_INTERACTIVE, 0, 1,
++		"--non-inter",
++		"Noninteractive",
++		NULL,
++		"Don't ask anything, exit on missing options",
++		NULL
++	}, {
++		0, 0, 0, NULL, NULL, NULL, NULL, NULL
++	}
++};
++
++static void read_config_file(char *name, const char **configs, int missingok)
++{
++	FILE *f;
++	char *line = NULL;
++	ssize_t line_length = 0;
++	int linenum = 0;
++
++	f = fopen(name, "r");
++	if (missingok && f == NULL && errno == ENOENT)
++		return;
++	if (f == NULL)
++		error(1, errno, "couldn't open `%s'", name);
++	for (;;) {
++		ssize_t llen;
++		int i;
++
++		llen = getline(&line, &line_length, f);
++		if (llen == -1 && feof(f))
++			break;
++		if (llen == -1)
++			error(1, errno, "reading `%s'", name);
++		if (line[llen - 1] == '\n')
++			line[llen - 1] = 0;
++		linenum++;
++		for (i = 0; config_names[i].name != NULL; i++) {
++			if (config_names[i].nm == CONFIG_NONE)
++				continue;
++			if (strncasecmp(config_names[i].name, line,
++					strlen(config_names[i].name)) == 0) {
++				// boolean implementation, using harmles pointer targets as true
++				if (!config_names[i].needsArgument) {
++					configs[config_names[i].nm] = config_names[i].name;
++					break;
++				}
++				if (configs[config_names[i].nm] == NULL)
++					configs[config_names[i].nm] =
++						strdup(line + strlen(config_names[i].name));
++				if (configs[config_names[i].nm] == NULL)
++					error(1, errno, "can't allocate memory");
++				break;
++			}
++		}
++		if (config_names[i].name == NULL && line[0] != '#' && line[0] != 0)
++			error(0, 0, "warning: unknown configuration directive in %s at line %d",
++				name, linenum);
++	}
++}
++
++static void print_desc(const char *pre, const char *text)
++{
++	const char *p, *q;
++
++	for (p = text, q = strchr(p, '\n'); q; p = q+1, q = strchr(p, '\n'))
++		printf("%s%.*s\n", pre, q-p, p);
++
++	if (*p != '\0')
++		printf("%s%s\n", pre, p);
++}
++
++static void print_usage(char *argv0, int long_help)
++{
++	int c;
++
++	printf("Usage: %s [--version] [--print-config] [--help] [--long-help] [options] [config file]\n\n",
++		argv0);
++	printf("Legend:\n");
++	for (c = 0; config_names[c].name != NULL; c++) {
++		if (config_names[c].lvl > long_help)
++			continue;
++
++		printf("  %s %s\n"
++			"  %s%s\n",
++			(config_names[c].option == NULL ? "(configfile only option)" :
++				config_names[c].option),
++			((config_names[c].type == NULL || config_names[c].option == NULL) ?
++				"" : config_names[c].type),
++			config_names[c].name,
++			(config_names[c].type == NULL ? "" : config_names[c].type));
++		print_desc("      ", config_names[c].desc);
++
++		if (config_names[c].get_def != NULL)
++			printf("    Default: %s\n", config_names[c].get_def());
++
++		printf("\n");
++	}
++	printf("Report bugs to vpnc@unix-ag.uni-kl.de\n");
++}
++
++static void print_version(void)
++{
++	unsigned int i;
++
++	printf("vpnc version " VERSION "\n");
++	printf("Copyright (C) 2002-2004 Geoffrey Keating, Maurice Massar\n");
++	printf("vpnc comes with NO WARRANTY, to the extent permitted by law.\n"
++		"You may redistribute copies of vpnc under the terms of the GNU General\n"
++		"Public License.  For more information about these matters, see the files\n"
++		"named COPYING.\n");
++	printf("\n");
++
++	printf("Supported DH-Groups:");
++	for (i = 0; supp_dh_group[i].name != NULL; i++)
++		printf(" %s", supp_dh_group[i].name);
++	printf("\n");
++
++	printf("Supported Hash-Methods:");
++	for (i = 0; supp_hash[i].name != NULL; i++)
++		printf(" %s", supp_hash[i].name);
++	printf("\n");
++
++	printf("Supported Encryptions:");
++	for (i = 0; supp_crypt[i].name != NULL; i++)
++		printf(" %s", supp_crypt[i].name);
++	printf("\n");
++}
++
++void do_config(int argc, char **argv)
++{
++	char *s;
++	int i, c, known, s_len;
++	int print_config = 0;
++
++	for (i = 1; i < argc; i++) {
++		if (argv[i][0] != '-') {
++			read_config_file(argv[i], config, 0);
++			continue;
++		}
++
++		known = 0;
++
++		for (c = 0; config_names[c].name != NULL && !known; c++) {
++			if (config_names[c].option == NULL
++				|| config_names[c].nm == CONFIG_NONE
++				|| strncmp(argv[i], config_names[c].option,
++					strlen(config_names[c].option)) != 0)
++				continue;
++
++			s = NULL;
++
++			known = 1;
++			if (argv[i][strlen(config_names[c].option)] == '=')
++				s = argv[i] + strlen(config_names[c].option) + 1;
++			else if (argv[i][strlen(config_names[c].option)] == 0) {
++				if (config_names[c].needsArgument) {
++					if (i + 1 < argc)
++						s = argv[++i];
++					else
++						known = 0;
++				} else
++					s = argv[i]; /* no arg, fill in something */
++			} else
++				known = 0;
++			if (known)
++				config[config_names[c].nm] = s;
++		}
++
++		if (!known && strcmp(argv[i], "--version") == 0) {
++			print_version();
++			exit(0);
++		}
++		if (!known && strcmp(argv[i], "--print-config") == 0) {
++			print_config = 1;
++			known = 1;
++		}
++		if (!known && strcmp(argv[i], "--help") == 0) {
++			print_usage(argv[0], 0);
++			exit(0);
++		}
++		if (!known && strcmp(argv[i], "--long-help") == 0) {
++			print_usage(argv[0], 1);
++			exit(0);
++		}
++		if (!known) {
++			printf("%s: unknown option %s\n\n", argv[0], argv[i]);
++
++			print_usage(argv[0], 1);
++			exit(1);
++		}
++	}
++
++	read_config_file("/etc/vpnc/default.conf", config, 1);
++	read_config_file("/etc/vpnc.conf", config, 1);
++
++	if (!print_config)
++		for (i = 0; config_names[i].name != NULL; i++)
++			if (!config[config_names[i].nm] && i != CONFIG_NONE
++				&& config_names[i].get_def != NULL)
++				config[config_names[i].nm] = config_names[i].get_def();
++
++	opt_debug = (config[CONFIG_DEBUG]) ? atoi(config[CONFIG_DEBUG]) : 0;
++	opt_nd = (config[CONFIG_ND]) ? 1 : 0;
++	opt_1des = (config[CONFIG_ENABLE_1DES]) ? 1 : 0;
++
++	if (opt_debug >= 99) {
++		printf("WARNING! active debug level is >= 99, output includes username and password (hex encoded)\n");
++		fprintf(stderr,
++			"WARNING! active debug level is >= 99, output includes username and password (hex encoded)\n");
++	}
++
++	for (i = 0; i < LAST_CONFIG; i++) {
++		if (config[i] != NULL || config[CONFIG_NON_INTERACTIVE] != NULL)
++			continue;
++		if (config[CONFIG_XAUTH_INTERACTIVE] && i == CONFIG_XAUTH_PASSWORD)
++			continue;
++		
++		s = NULL;
++		s_len = 0;
++
++		switch (i) {
++		case CONFIG_IPSEC_GATEWAY:
++			printf("Enter IPSec gateway address: ");
++			break;
++		case CONFIG_IPSEC_ID:
++			printf("Enter IPSec ID for %s: ", config[CONFIG_IPSEC_GATEWAY]);
++			break;
++		case CONFIG_IPSEC_SECRET:
++			printf("Enter IPSec secret for %s@%s: ",
++				config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_GATEWAY]);
++			break;
++		case CONFIG_XAUTH_USERNAME:
++			printf("Enter username for %s: ", config[CONFIG_IPSEC_GATEWAY]);
++			break;
++		case CONFIG_XAUTH_PASSWORD:
++			printf("Enter password for %s@%s: ",
++				config[CONFIG_XAUTH_USERNAME],
++				config[CONFIG_IPSEC_GATEWAY]);
++			break;
++		}
++		fflush(stdout);
++		switch (i) {
++		case CONFIG_IPSEC_SECRET:
++		case CONFIG_XAUTH_PASSWORD:
++			s = strdup(getpass(""));
++			break;
++		case CONFIG_IPSEC_GATEWAY:
++		case CONFIG_IPSEC_ID:
++		case CONFIG_XAUTH_USERNAME:
++			getline(&s, &s_len, stdin);
++		}
++		if (s != NULL && s[strlen(s) - 1] == '\n')
++			s[strlen(s) - 1] = 0;
++		config[i] = s;
++	}
++
++	if (print_config) {
++		fprintf(stderr, "vpnc.conf:\n\n");
++		for (i = 0; config_names[i].name != NULL; i++) {
++			if (config[config_names[i].nm] == NULL)
++				continue;
++			printf("%s%s\n", config_names[i].name,
++				config_names[i].needsArgument ?
++					config[config_names[i].nm] : "");
++		}
++		exit(0);
++	}
++
++	if (!config[CONFIG_IPSEC_GATEWAY])
++		error(1, 0, "missing IPSec gatway address");
++	if (!config[CONFIG_IPSEC_ID])
++		error(1, 0, "missing IPSec ID");
++	if (!config[CONFIG_IPSEC_SECRET])
++		error(1, 0, "missing IPSec secret");
++	if (!config[CONFIG_XAUTH_USERNAME])
++		error(1, 0, "missing Xauth username");
++	if (!config[CONFIG_XAUTH_PASSWORD] && !config[CONFIG_XAUTH_INTERACTIVE])
++		error(1, 0, "missing Xauth password");
++	if (get_dh_group_ike() == NULL)
++		error(1, 0, "IKE DH Group \"%s\" unsupported\n", config[CONFIG_IKE_DH]);
++	if (get_dh_group_ipsec(-1) == NULL)
++		error(1, 0, "Perfect Forward Secrecy \"%s\" unsupported\n",
++			config[CONFIG_IPSEC_PFS]);
++	if (get_dh_group_ike()->ike_sa_id == 0)
++		error(1, 0, "IKE DH Group must not be nopfs\n");
++
++	return;
++}
+diff -Nurd vpnc-0.2-rm+zomb.1/config.h new/config.h
+--- vpnc-0.2-rm+zomb.1/config.h	1970-01-01 01:00:00.000000000 +0100
++++ new/config.h	2004-05-30 17:42:39.000000000 +0200
+@@ -0,0 +1,62 @@
++/* IPSec VPN client compatible with Cisco equipment.
++   Copyright (C) 2004 Maurice Massar
++
++   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.
++   
++   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.
++   
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software
++   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#ifndef __CONFIG_H__
++#define __CONFIG_H__
++
++enum config_enum {
++	CONFIG_NONE,
++	CONFIG_CONFIG_SCRIPT,
++	CONFIG_DEBUG,
++	CONFIG_DOMAIN,
++	CONFIG_ENABLE_1DES,
++	CONFIG_ND,
++	CONFIG_NON_INTERACTIVE,
++	CONFIG_PID_FILE,
++	CONFIG_LOCAL_PORT,
++	CONFIG_VERSION,
++	CONFIG_IF_NAME,
++	CONFIG_IKE_DH,
++	CONFIG_IPSEC_PFS,
++	CONFIG_IPSEC_GATEWAY,
++	CONFIG_IPSEC_ID,
++	CONFIG_IPSEC_SECRET,
++	CONFIG_XAUTH_USERNAME,
++	CONFIG_XAUTH_PASSWORD,
++	CONFIG_XAUTH_INTERACTIVE,
++	LAST_CONFIG
++};
++
++enum hex_dump_enum {
++	UINT8 = -1,
++	UINT16 = -2,
++	UINT32 = -4
++};
++
++extern const char *config[LAST_CONFIG];
++
++extern int opt_debug;
++extern int opt_nd;
++extern int opt_1des;
++
++#define DEBUG(lvl, a) do {if (opt_debug >= (lvl)) {a;}} while (0)
++
++extern void hex_dump(const char *str, const void *data, ssize_t len);
++extern void do_config(int argc, char **argv);
++
++#endif
+diff -Nurd vpnc-0.2-rm+zomb.1/dh.c new/dh.c
+--- vpnc-0.2-rm+zomb.1/dh.c	2003-12-17 18:50:09.000000000 +0100
++++ new/dh.c	2004-05-30 14:32:32.000000000 +0200
+@@ -39,10 +39,9 @@
+  * Returns the length of our exchange value.
+  */
+ 
+-int
+-dh_getlen (struct group *group)
++int dh_getlen(struct group *group)
+ {
+-  return group->getlen (group);
++	return group->getlen(group);
+ }
+ 
+ /*
+@@ -51,15 +50,14 @@
+  * means the application has to save the exchange value itself,
+  * dh_create_exchange should only be called once.
+  */
+-int
+-dh_create_exchange (struct group *group, unsigned char *buf)
++int dh_create_exchange(struct group *group, unsigned char *buf)
+ {
+-  if (group->setrandom (group, group->c))
+-    return -1;
+-  if (group->operation (group, group->a, group->gen, group->c))
+-    return -1;
+-  group->getraw (group, group->a, buf);
+-  return 0;
++	if (group->setrandom(group, group->c))
++		return -1;
++	if (group->operation(group, group->a, group->gen, group->c))
++		return -1;
++	group->getraw(group, group->a, buf);
++	return 0;
+ }
+ 
+ /*
+@@ -67,13 +65,12 @@
+  * is the exchange value offered by the other party. No length verification
+  * is done for the value, the application has to do that.
+  */
+-int
+-dh_create_shared (struct group *group, unsigned char *secret, unsigned char *exchange)
++int dh_create_shared(struct group *group, unsigned char *secret, unsigned char *exchange)
+ {
+-  if (group->setraw (group, group->b, exchange, group->getlen (group)))
+-    return -1;
+-  if (group->operation (group, group->a, group->b, group->c))
+-    return -1;
+-  group->getraw (group, group->a, secret);
+-  return 0;
++	if (group->setraw(group, group->b, exchange, group->getlen(group)))
++		return -1;
++	if (group->operation(group, group->a, group->b, group->c))
++		return -1;
++	group->getraw(group, group->a, secret);
++	return 0;
+ }
+diff -Nurd vpnc-0.2-rm+zomb.1/dh.h new/dh.h
+--- vpnc-0.2-rm+zomb.1/dh.h	2003-10-20 01:57:04.000000000 +0200
++++ new/dh.h	2004-06-10 11:19:53.000000000 +0200
+@@ -31,15 +31,15 @@
+  * This code was written under funding by Ericsson Radio Systems.
+  */
+ 
+-#ifndef _DH_H_
+-#define _DH_H_
++#ifndef __DH_H__
++#define __DH_H__
+ 
+ #include <sys/types.h>
+ 
+ struct group;
+ 
+-int dh_getlen (struct group *);
+-int dh_create_exchange (struct group *, unsigned char *);
+-int dh_create_shared (struct group *, unsigned char *, unsigned char *);
++int dh_getlen(struct group *);
++int dh_create_exchange(struct group *, unsigned char *);
++int dh_create_shared(struct group *, unsigned char *, unsigned char *);
+ 
+-#endif /* _DH_H_ */
++#endif
+diff -Nurd vpnc-0.2-rm+zomb.1/isakmp.h new/isakmp.h
+--- vpnc-0.2-rm+zomb.1/isakmp.h	2004-05-02 01:26:20.000000000 +0200
++++ new/isakmp.h	2004-06-10 11:19:53.000000000 +0200
+@@ -16,6 +16,9 @@
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+ 
++#ifndef __ISAKMP_H__
++#define __ISAKMP_H__
++
+ /* Flag bits for header.  */
+ #define ISAKMP_FLAG_E	0x1
+ #define ISAKMP_FLAG_C	0x2
+@@ -23,35 +26,35 @@
+ 
+ /* Payload types */
+ enum isakmp_payload_enum {
+-  ISAKMP_PAYLOAD_NONE = 0,
+-  ISAKMP_PAYLOAD_SA,
+-  ISAKMP_PAYLOAD_P,
+-  ISAKMP_PAYLOAD_T,
+-  ISAKMP_PAYLOAD_KE,
+-  ISAKMP_PAYLOAD_ID,
+-  ISAKMP_PAYLOAD_CERT,
+-  ISAKMP_PAYLOAD_CR,
+-  ISAKMP_PAYLOAD_HASH,
+-  ISAKMP_PAYLOAD_SIG,
+-  ISAKMP_PAYLOAD_NONCE,
+-  ISAKMP_PAYLOAD_N,
+-  ISAKMP_PAYLOAD_D,
+-  ISAKMP_PAYLOAD_VID,
+-  ISAKMP_PAYLOAD_MODECFG_ATTR,
+-  LAST_ISAKMP_PAYLOAD
++	ISAKMP_PAYLOAD_NONE = 0,
++	ISAKMP_PAYLOAD_SA,
++	ISAKMP_PAYLOAD_P,
++	ISAKMP_PAYLOAD_T,
++	ISAKMP_PAYLOAD_KE,
++	ISAKMP_PAYLOAD_ID,
++	ISAKMP_PAYLOAD_CERT,
++	ISAKMP_PAYLOAD_CR,
++	ISAKMP_PAYLOAD_HASH,
++	ISAKMP_PAYLOAD_SIG,
++	ISAKMP_PAYLOAD_NONCE,
++	ISAKMP_PAYLOAD_N,
++	ISAKMP_PAYLOAD_D,
++	ISAKMP_PAYLOAD_VID,
++	ISAKMP_PAYLOAD_MODECFG_ATTR,
++	LAST_ISAKMP_PAYLOAD
+ };
+ 
+ /* Exchange types.  */
+ enum isakmp_exchange_enum {
+-  ISAKMP_EXCHANGE_NONE = 0,
+-  ISAKMP_EXCHANGE_BASE,
+-  ISAKMP_EXCHANGE_IDENTITY,
+-  ISAKMP_EXCHANGE_AUTH_ONLY,
+-  ISAKMP_EXCHANGE_AGGRESSIVE,
+-  ISAKMP_EXCHANGE_INFORMATIONAL,
+-  ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
+-  ISAKMP_EXCHANGE_IKE_QUICK = 32,
+-  ISAKMP_EXCHANGE_IKE_NEW_GROUP
++	ISAKMP_EXCHANGE_NONE = 0,
++	ISAKMP_EXCHANGE_BASE,
++	ISAKMP_EXCHANGE_IDENTITY,
++	ISAKMP_EXCHANGE_AUTH_ONLY,
++	ISAKMP_EXCHANGE_AGGRESSIVE,
++	ISAKMP_EXCHANGE_INFORMATIONAL,
++	ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
++	ISAKMP_EXCHANGE_IKE_QUICK = 32,
++	ISAKMP_EXCHANGE_IKE_NEW_GROUP
+ };
+ 
+ /* DOI types.  */
+@@ -60,125 +63,125 @@
+ 
+ /* Notify message types.  */
+ enum isakmp_notify_enum {
+-  ISAKMP_N_INVALID_PAYLOAD_TYPE = 1,
+-  ISAKMP_N_DOI_NOT_SUPPORTED,
+-  ISAKMP_N_SITUATION_NOT_SUPPORTED,
+-  ISAKMP_N_INVALID_COOKIE,
+-  ISAKMP_N_INVALID_MAJOR_VERSION,
+-  ISAKMP_N_INVALID_MINOR_VERSION,
+-  ISAKMP_N_INVALID_EXCHANGE_TYPE,
+-  ISAKMP_N_INVALID_FLAGS,
+-  ISAKMP_N_INVALID_MESSAGE_ID,
+-  ISAKMP_N_INVALID_PROTOCOL_ID,
+-  ISAKMP_N_INVALID_SPI,
+-  ISAKMP_N_INVALID_TRANSFORM_ID,
+-  ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED,
+-  ISAKMP_N_NO_PROPOSAL_CHOSEN,
+-  ISAKMP_N_BAD_PROPOSAL_SYNTAX,
+-  ISAKMP_N_PAYLOAD_MALFORMED,
+-  ISAKMP_N_INVALID_KEY_INFORMATION,
+-  ISAKMP_N_INVALID_ID_INFORMATION,
+-  ISAKMP_N_INVALID_CERT_ENCODING,
+-  ISAKMP_N_INVALID_CERTIFICATE,
+-  ISAKMP_N_CERT_TYPE_UNSUPPORTED,
+-  ISAKMP_N_INVALID_CERT_AUTHORITY,
+-  ISAKMP_N_INVALID_HASH_INFORMATION,
+-  ISAKMP_N_AUTHENTICATION_FAILED,
+-  ISAKMP_N_INVALID_SIGNATURE,
+-  ISAKMP_N_ADDRESS_NOTIFICATION,
+-  ISAKMP_N_NOTIFY_SA_LIFETIME,
+-  ISAKMP_N_CERTIFICATE_UNAVAILABLE,
+-  ISAKMP_N_UNSUPPORTED_EXCHANGE_TYPE,
+-  ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS,
+-  ISAKMP_N_CONNECTED = 16384,
+-  ISAKMP_N_IPSEC_RESPONDER_LIFETIME = 24576,
+-  ISAKMP_N_IPSEC_REPLAY_STATUS,
+-  ISAKMP_N_IPSEC_INITIAL_CONTACT,
+-  ISAKMP_N_CISCO_LOAD_BALANCE = 40501
++	ISAKMP_N_INVALID_PAYLOAD_TYPE = 1,
++	ISAKMP_N_DOI_NOT_SUPPORTED,
++	ISAKMP_N_SITUATION_NOT_SUPPORTED,
++	ISAKMP_N_INVALID_COOKIE,
++	ISAKMP_N_INVALID_MAJOR_VERSION,
++	ISAKMP_N_INVALID_MINOR_VERSION,
++	ISAKMP_N_INVALID_EXCHANGE_TYPE,
++	ISAKMP_N_INVALID_FLAGS,
++	ISAKMP_N_INVALID_MESSAGE_ID,
++	ISAKMP_N_INVALID_PROTOCOL_ID,
++	ISAKMP_N_INVALID_SPI,
++	ISAKMP_N_INVALID_TRANSFORM_ID,
++	ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED,
++	ISAKMP_N_NO_PROPOSAL_CHOSEN,
++	ISAKMP_N_BAD_PROPOSAL_SYNTAX,
++	ISAKMP_N_PAYLOAD_MALFORMED,
++	ISAKMP_N_INVALID_KEY_INFORMATION,
++	ISAKMP_N_INVALID_ID_INFORMATION,
++	ISAKMP_N_INVALID_CERT_ENCODING,
++	ISAKMP_N_INVALID_CERTIFICATE,
++	ISAKMP_N_CERT_TYPE_UNSUPPORTED,
++	ISAKMP_N_INVALID_CERT_AUTHORITY,
++	ISAKMP_N_INVALID_HASH_INFORMATION,
++	ISAKMP_N_AUTHENTICATION_FAILED,
++	ISAKMP_N_INVALID_SIGNATURE,
++	ISAKMP_N_ADDRESS_NOTIFICATION,
++	ISAKMP_N_NOTIFY_SA_LIFETIME,
++	ISAKMP_N_CERTIFICATE_UNAVAILABLE,
++	ISAKMP_N_UNSUPPORTED_EXCHANGE_TYPE,
++	ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS,
++	ISAKMP_N_CONNECTED = 16384,
++	ISAKMP_N_IPSEC_RESPONDER_LIFETIME = 24576,
++	ISAKMP_N_IPSEC_REPLAY_STATUS,
++	ISAKMP_N_IPSEC_INITIAL_CONTACT,
++	ISAKMP_N_CISCO_LOAD_BALANCE = 40501
+ };
+ 
+ /* IKE attribute types.  */
+ enum {
+-  IKE_ATTRIB_ENC = 1,
+-  IKE_ATTRIB_HASH,
+-  IKE_ATTRIB_AUTH_METHOD,
+-  IKE_ATTRIB_GROUP_DESC,
+-  IKE_ATTRIB_GROUP_TYPE,
+-  IKE_ATTRIB_GROUP_PRIME,
+-  IKE_ATTRIB_GROUP_GEN_1,
+-  IKE_ATTRIB_GROUP_GEN_2,
+-  IKE_ATTRIB_GROUP_CURVE_A,
+-  IKE_ATTRIB_GROUP_CURVE_B,
+-  IKE_ATTRIB_LIFE_TYPE,
+-  IKE_ATTRIB_LIFE_DURATION,
+-  IKE_ATTRIB_PRF,
+-  IKE_ATTRIB_KEY_LENGTH,
+-  IKE_ATTRIB_FIELD_SIZE,
+-  IKE_ATTRIB_GROUP_ORDER,
+-  IKE_ATTRIB_BLOCK_SIZE
++	IKE_ATTRIB_ENC = 1,
++	IKE_ATTRIB_HASH,
++	IKE_ATTRIB_AUTH_METHOD,
++	IKE_ATTRIB_GROUP_DESC,
++	IKE_ATTRIB_GROUP_TYPE,
++	IKE_ATTRIB_GROUP_PRIME,
++	IKE_ATTRIB_GROUP_GEN_1,
++	IKE_ATTRIB_GROUP_GEN_2,
++	IKE_ATTRIB_GROUP_CURVE_A,
++	IKE_ATTRIB_GROUP_CURVE_B,
++	IKE_ATTRIB_LIFE_TYPE,
++	IKE_ATTRIB_LIFE_DURATION,
++	IKE_ATTRIB_PRF,
++	IKE_ATTRIB_KEY_LENGTH,
++	IKE_ATTRIB_FIELD_SIZE,
++	IKE_ATTRIB_GROUP_ORDER,
++	IKE_ATTRIB_BLOCK_SIZE
+ };
+ 
+ /* IKE encryption algorithm IDs.  */
+ enum {
+-  IKE_ENC_DES_CBC = 1,
+-  IKE_ENC_IDEA_CBC,
+-  IKE_ENC_BLOWFISH_CBC,
+-  IKE_ENC_RC5_R16_B16_CBC,
+-  IKE_ENC_3DES_CBC,
+-  IKE_ENC_CAST_CBC,
+-  IKE_ENC_AES_CBC
++	IKE_ENC_DES_CBC = 1,
++	IKE_ENC_IDEA_CBC,
++	IKE_ENC_BLOWFISH_CBC,
++	IKE_ENC_RC5_R16_B16_CBC,
++	IKE_ENC_3DES_CBC,
++	IKE_ENC_CAST_CBC,
++	IKE_ENC_AES_CBC
+ };
+ 
+ /* IKE hash algorithm IDs.  */
+ enum {
+-  IKE_HASH_MD5 = 1,
+-  IKE_HASH_SHA,
+-  IKE_HASH_TIGER,
+-  IKE_HASH_SHA2_256,
+-  IKE_HASH_SHA2_384,
+-  IKE_HASH_SHA2_512
++	IKE_HASH_MD5 = 1,
++	IKE_HASH_SHA,
++	IKE_HASH_TIGER,
++	IKE_HASH_SHA2_256,
++	IKE_HASH_SHA2_384,
++	IKE_HASH_SHA2_512
+ };
+ 
+ /* IKE authentication method IDs.  */
+ enum {
+-  IKE_AUTH_PRESHARED = 1,
+-  IKE_AUTH_DSS,
+-  IKE_AUTH_RSA_SIG,
+-  IKE_AUTH_RSA_ENC,
+-  IKE_AUTH_RSA_ENC_2,
+-  IKE_AUTH_EL_GAMAL_ENC,
+-  IKE_AUTH_EL_GAMAL_ENC_REV,
+-  IKE_AUTH_ECDSA_SIG
++	IKE_AUTH_PRESHARED = 1,
++	IKE_AUTH_DSS,
++	IKE_AUTH_RSA_SIG,
++	IKE_AUTH_RSA_ENC,
++	IKE_AUTH_RSA_ENC_2,
++	IKE_AUTH_EL_GAMAL_ENC,
++	IKE_AUTH_EL_GAMAL_ENC_REV,
++	IKE_AUTH_ECDSA_SIG
+ };
+ 
+ /* IKE group IDs.  */
+ enum {
+-  IKE_GROUP_MODP_768 = 1,
+-  IKE_GROUP_MODP_1024,
+-  IKE_GROUP_EC2N_155,
+-  IKE_GROUP_EC2N_185,
+-  IKE_GROUP_MODP_1536,
+-  IKE_GROUP_EC2N_163sect,
+-  IKE_GROUP_EC2N_163K,
+-  IKE_GROUP_EC2N_283sect,
+-  IKE_GROUP_EC2N_283K,
+-  IKE_GROUP_EC2N_409sect,
+-  IKE_GROUP_EC2N_409K,
+-  IKE_GROUP_EC2N_571sect,
+-  IKE_GROUP_EC2N_571K,
++	IKE_GROUP_MODP_768 = 1,
++	IKE_GROUP_MODP_1024,
++	IKE_GROUP_EC2N_155,
++	IKE_GROUP_EC2N_185,
++	IKE_GROUP_MODP_1536,
++	IKE_GROUP_EC2N_163sect,
++	IKE_GROUP_EC2N_163K,
++	IKE_GROUP_EC2N_283sect,
++	IKE_GROUP_EC2N_283K,
++	IKE_GROUP_EC2N_409sect,
++	IKE_GROUP_EC2N_409K,
++	IKE_GROUP_EC2N_571sect,
++	IKE_GROUP_EC2N_571K,
+ };
+ 
+ /* IKE group type IDs.  */
+ enum {
+-  IKE_GROUP_TYPE_MODP = 1,
+-  IKE_GROUP_TYPE_ECP,
+-  IKE_GROUP_TYPE_EC2N
++	IKE_GROUP_TYPE_MODP = 1,
++	IKE_GROUP_TYPE_ECP,
++	IKE_GROUP_TYPE_EC2N
+ };
+ 
+ /* IKE life type IDs.  */
+ enum {
+-  IKE_LIFE_TYPE_SECONDS = 1,
+-  IKE_LIFE_TYPE_K
++	IKE_LIFE_TYPE_SECONDS = 1,
++	IKE_LIFE_TYPE_K
+ };
+ 
+ /* IPSEC situation masks.  */
+@@ -188,114 +191,113 @@
+ 
+ /* IPSEC Identification types.  */
+ enum {
+-  ISAKMP_IPSEC_ID_RESERVED = 0,
+-  ISAKMP_IPSEC_ID_IPV4_ADDR,
+-  ISAKMP_IPSEC_ID_FQDN,
+-  ISAKMP_IPSEC_ID_USER_FQDN,
+-  ISAKMP_IPSEC_ID_IPV4_ADDR_SUBNET,
+-  ISAKMP_IPSEC_ID_IPV6_ADDR,
+-  ISAKMP_IPSEC_ID_IPV6_ADDR_SUBNET,
+-  ISAKMP_IPSEC_ID_IPV4_ADDR_RANGE,
+-  ISAKMP_IPSEC_ID_IPV6_ADDR_RANGE,
+-  ISAKMP_IPSEC_ID_DER_ASN1_DN,
+-  ISAKMP_IPSEC_ID_DER_ASN1_GN,
+-  ISAKMP_IPSEC_ID_KEY_ID
++	ISAKMP_IPSEC_ID_RESERVED = 0,
++	ISAKMP_IPSEC_ID_IPV4_ADDR,
++	ISAKMP_IPSEC_ID_FQDN,
++	ISAKMP_IPSEC_ID_USER_FQDN,
++	ISAKMP_IPSEC_ID_IPV4_ADDR_SUBNET,
++	ISAKMP_IPSEC_ID_IPV6_ADDR,
++	ISAKMP_IPSEC_ID_IPV6_ADDR_SUBNET,
++	ISAKMP_IPSEC_ID_IPV4_ADDR_RANGE,
++	ISAKMP_IPSEC_ID_IPV6_ADDR_RANGE,
++	ISAKMP_IPSEC_ID_DER_ASN1_DN,
++	ISAKMP_IPSEC_ID_DER_ASN1_GN,
++	ISAKMP_IPSEC_ID_KEY_ID
+ };
+ 
+ /* IPSEC protocol IDs.  */
+ enum {
+-  ISAKMP_IPSEC_PROTO_RESERVED = 0,
+-  ISAKMP_IPSEC_PROTO_ISAKMP,
+-  ISAKMP_IPSEC_PROTO_IPSEC_AH,
+-  ISAKMP_IPSEC_PROTO_IPSEC_ESP,
+-  ISAKMP_IPSEC_PROTO_IPCOMP
++	ISAKMP_IPSEC_PROTO_RESERVED = 0,
++	ISAKMP_IPSEC_PROTO_ISAKMP,
++	ISAKMP_IPSEC_PROTO_IPSEC_AH,
++	ISAKMP_IPSEC_PROTO_IPSEC_ESP,
++	ISAKMP_IPSEC_PROTO_IPCOMP
+ };
+ 
+ /* IPSEC transform IDs.  */
+ enum {
+-  ISAKMP_IPSEC_KEY_RESERVED = 0,
+-  ISAKMP_IPSEC_KEY_IKE
++	ISAKMP_IPSEC_KEY_RESERVED = 0,
++	ISAKMP_IPSEC_KEY_IKE
+ };
+ 
+ /* IPSEC AH IDs.  */
+ enum {
+-  ISAKMP_IPSEC_AH_RESERVED = 0,
+-  ISAKMP_IPSEC_AH_MD5 = 2,
+-  ISAKMP_IPSEC_AH_SHA,
+-  ISAKMP_IPSEC_AH_DES,
+-  ISAKMP_IPSEC_AH_SHA2_256,
+-  ISAKMP_IPSEC_AH_SHA2_384,
+-  ISAKMP_IPSEC_AH_SHA2_512,
+-  ISAKMP_IPSEC_AH_RIPEMD
++	ISAKMP_IPSEC_AH_RESERVED = 0,
++	ISAKMP_IPSEC_AH_MD5 = 2,
++	ISAKMP_IPSEC_AH_SHA,
++	ISAKMP_IPSEC_AH_DES,
++	ISAKMP_IPSEC_AH_SHA2_256,
++	ISAKMP_IPSEC_AH_SHA2_384,
++	ISAKMP_IPSEC_AH_SHA2_512,
++	ISAKMP_IPSEC_AH_RIPEMD
+ };
+ 
+ /* IPSEC ESP IDs.  */
+ enum {
+-  ISAKMP_IPSEC_ESP_RESERVED = 0,
+-  ISAKMP_IPSEC_ESP_DES_IV64,
+-  ISAKMP_IPSEC_ESP_DES,
+-  ISAKMP_IPSEC_ESP_3DES,
+-  ISAKMP_IPSEC_ESP_RC5,
+-  ISAKMP_IPSEC_ESP_IDEA,
+-  ISAKMP_IPSEC_ESP_CAST,
+-  ISAKMP_IPSEC_ESP_BLOWFISH,
+-  ISAKMP_IPSEC_ESP_3IDEA,
+-  ISAKMP_IPSEC_ESP_DES_IV32,
+-  ISAKMP_IPSEC_ESP_RC4,
+-  ISAKMP_IPSEC_ESP_NULL,
+-  ISAKMP_IPSEC_ESP_AES,
+-  ISAKMP_IPSEC_ESP_AES_128_CTR,
+-  ISAKMP_IPSEC_ESP_AES_MARS = 249,
+-  ISAKMP_IPSEC_ESP_AES_RC6,
+-  ISAKMP_IPSEC_ESP_AES_RIJNDAEL,
+-  ISAKMP_IPSEC_ESP_AES_SERPENT,
+-  ISAKMP_IPSEC_ESP_AES_TWOFISH,
++	ISAKMP_IPSEC_ESP_RESERVED = 0,
++	ISAKMP_IPSEC_ESP_DES_IV64,
++	ISAKMP_IPSEC_ESP_DES,
++	ISAKMP_IPSEC_ESP_3DES,
++	ISAKMP_IPSEC_ESP_RC5,
++	ISAKMP_IPSEC_ESP_IDEA,
++	ISAKMP_IPSEC_ESP_CAST,
++	ISAKMP_IPSEC_ESP_BLOWFISH,
++	ISAKMP_IPSEC_ESP_3IDEA,
++	ISAKMP_IPSEC_ESP_DES_IV32,
++	ISAKMP_IPSEC_ESP_RC4,
++	ISAKMP_IPSEC_ESP_NULL,
++	ISAKMP_IPSEC_ESP_AES,
++	ISAKMP_IPSEC_ESP_AES_128_CTR,
++	ISAKMP_IPSEC_ESP_AES_MARS = 249,
++	ISAKMP_IPSEC_ESP_AES_RC6,
++	ISAKMP_IPSEC_ESP_AES_RIJNDAEL,
++	ISAKMP_IPSEC_ESP_AES_SERPENT,
++	ISAKMP_IPSEC_ESP_AES_TWOFISH,
+ };
+ 
+ /* IPSEC attribute types.  */
+ enum {
+-  ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE = 1,
+-  ISAKMP_IPSEC_ATTRIB_SA_LIFE_DURATION,
+-  ISAKMP_IPSEC_ATTRIB_GROUP_DESC,
+-  ISAKMP_IPSEC_ATTRIB_ENCAP_MODE,
+-  ISAKMP_IPSEC_ATTRIB_AUTH_ALG,
+-  ISAKMP_IPSEC_ATTRIB_KEY_LENGTH,
+-  ISAKMP_IPSEC_ATTRIB_KEY_ROUNDS,
+-  ISAKMP_IPSEC_ATTRIB_COMP_DICT_SIZE,
+-  ISAKMP_IPSEC_ATTRIB_COMP_PRIVATE_ALG,
+-  ISAKMP_IPSEC_ATTRIB_ECN_TUNNEL
++	ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE = 1,
++	ISAKMP_IPSEC_ATTRIB_SA_LIFE_DURATION,
++	ISAKMP_IPSEC_ATTRIB_GROUP_DESC,
++	ISAKMP_IPSEC_ATTRIB_ENCAP_MODE,
++	ISAKMP_IPSEC_ATTRIB_AUTH_ALG,
++	ISAKMP_IPSEC_ATTRIB_KEY_LENGTH,
++	ISAKMP_IPSEC_ATTRIB_KEY_ROUNDS,
++	ISAKMP_IPSEC_ATTRIB_COMP_DICT_SIZE,
++	ISAKMP_IPSEC_ATTRIB_COMP_PRIVATE_ALG,
++	ISAKMP_IPSEC_ATTRIB_ECN_TUNNEL
+ };
+ 
+ /* IPSEC compression IDs.  */
+ enum {
+-  ISAKMP_IPSEC_IPCOMP_RESERVED = 0,
+-  ISAKMP_IPSEC_IPCOMP_OUI,
+-  ISAKMP_IPSEC_IPCOMP_DEFLATE,
+-  ISAKMP_IPSEC_IPCOMP_LZS,
+-  ISAKMP_IPSEC_IPCOMP_V42BIS
++	ISAKMP_IPSEC_IPCOMP_RESERVED = 0,
++	ISAKMP_IPSEC_IPCOMP_OUI,
++	ISAKMP_IPSEC_IPCOMP_DEFLATE,
++	ISAKMP_IPSEC_IPCOMP_LZS,
++	ISAKMP_IPSEC_IPCOMP_V42BIS
+ };
+ 
+ /* IPSEC lifetime attribute values.  */
+ enum {
+-  IPSEC_LIFE_SECONDS = 1,
+-  IPSEC_LIFE_K
++	IPSEC_LIFE_SECONDS = 1,
++	IPSEC_LIFE_K
+ };
+ 
+ /* IPSEC encapsulation attribute numbers.  */
+ enum {
+-  IPSEC_ENCAP_TUNNEL = 1,
+-  IPSEC_ENCAP_TRANSPORT
++	IPSEC_ENCAP_TUNNEL = 1,
++	IPSEC_ENCAP_TRANSPORT
+ };
+ 
+ /* IPSEC authentication attribute numbers.  */
+ enum {
+-  IPSEC_AUTH_HMAC_MD5 = 1,
+-  IPSEC_AUTH_HMAC_SHA,
+-  IPSEC_AUTH_DES_MAC,
+-  IPSEC_AUTH_KPDK
++	IPSEC_AUTH_HMAC_MD5 = 1,
++	IPSEC_AUTH_HMAC_SHA,
++	IPSEC_AUTH_DES_MAC,
++	IPSEC_AUTH_KPDK
+ };
+ 
+-
+ /* Other numbers.  */
+ #define ISAKMP_COOKIE_LENGTH		8
+ #define ISAKMP_VERSION			0x10
+@@ -314,65 +316,67 @@
+ 	0x20, 0x48, 0x5F, 0x7F, 0x15, 0x5B, 0x4B, 0xC8 }
+ 
+ enum {
+-  XAUTH_AUTH_XAUTHInitPreShared = 65001,
+-  XAUTH_AUTH_XAUTHRespPreShared,
+-  XAUTH_AUTH_XAUTHInitDSS,
+-  XAUTH_AUTH_XAUTHRespDSS,
+-  XAUTH_AUTH_XAUTHInitRSA,
+-  XAUTH_AUTH_XAUTHRespRSA,
+-  XAUTH_AUTH_XAUTHInitRSAEncryption,
+-  XAUTH_AUTH_XAUTHRespRSAEncryption,
+-  XAUTH_AUTH_XAUTHInitRSARevisedEncryption,
+-  XAUTH_AUTH_XAUTHRespRSARevisedEncryption
++	XAUTH_AUTH_XAUTHInitPreShared = 65001,
++	XAUTH_AUTH_XAUTHRespPreShared,
++	XAUTH_AUTH_XAUTHInitDSS,
++	XAUTH_AUTH_XAUTHRespDSS,
++	XAUTH_AUTH_XAUTHInitRSA,
++	XAUTH_AUTH_XAUTHRespRSA,
++	XAUTH_AUTH_XAUTHInitRSAEncryption,
++	XAUTH_AUTH_XAUTHRespRSAEncryption,
++	XAUTH_AUTH_XAUTHInitRSARevisedEncryption,
++	XAUTH_AUTH_XAUTHRespRSARevisedEncryption
+ };
+ 
+ enum {
+-  ISAKMP_XAUTH_ATTRIB_TYPE = 16520,
+-  ISAKMP_XAUTH_ATTRIB_USER_NAME,
+-  ISAKMP_XAUTH_ATTRIB_USER_PASSWORD,
+-  ISAKMP_XAUTH_ATTRIB_PASSCODE,
+-  ISAKMP_XAUTH_ATTRIB_MESSAGE,
+-  ISAKMP_XAUTH_ATTRIB_CHALLENGE,
+-  ISAKMP_XAUTH_ATTRIB_DOMAIN,
+-  ISAKMP_XAUTH_ATTRIB_STATUS,
+-  ISAKMP_XAUTH_ATTRIB_NEXT_PIN,
+-  ISAKMP_XAUTH_ATTRIB_ANSWER,
+-  /* strange cisco things ... need docs! */
+-  ISAKMP_XAUTH_ATTRIB_CISCOEXT_VENDOR = 32136,
++	ISAKMP_XAUTH_ATTRIB_TYPE = 16520,
++	ISAKMP_XAUTH_ATTRIB_USER_NAME,
++	ISAKMP_XAUTH_ATTRIB_USER_PASSWORD,
++	ISAKMP_XAUTH_ATTRIB_PASSCODE,
++	ISAKMP_XAUTH_ATTRIB_MESSAGE,
++	ISAKMP_XAUTH_ATTRIB_CHALLENGE,
++	ISAKMP_XAUTH_ATTRIB_DOMAIN,
++	ISAKMP_XAUTH_ATTRIB_STATUS,
++	ISAKMP_XAUTH_ATTRIB_NEXT_PIN,
++	ISAKMP_XAUTH_ATTRIB_ANSWER, /* TYPE .. ANSWER is excluded from dump */
++	/* strange cisco things ... need docs! */
++	ISAKMP_XAUTH_ATTRIB_CISCOEXT_VENDOR = 32136,
+ };
+ 
+ /* Support for draft-ietf-ipsec-isakmp-mode-cfg-05.txt (yuk).  */
+ 
+ enum {
+-  ISAKMP_MODECFG_CFG_REQUEST = 1,
+-  ISAKMP_MODECFG_CFG_REPLY,
+-  ISAKMP_MODECFG_CFG_SET,
+-  ISAKMP_MODECFG_CFG_ACK
++	ISAKMP_MODECFG_CFG_REQUEST = 1,
++	ISAKMP_MODECFG_CFG_REPLY,
++	ISAKMP_MODECFG_CFG_SET,
++	ISAKMP_MODECFG_CFG_ACK
+ };
+ 
+ enum {
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_ADDRESS = 1,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NETMASK,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DNS,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NBNS,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_ADDRESS_EXPIRY,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DHCP,
+-  ISAKMP_MODECFG_ATTRIB_APPLICATION_VERSION,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_ADDRESS,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_NETMASK,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_DNS,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_NBNS,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_DHCP,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_SUBNET,
+-  ISAKMP_MODECFG_ATTRIB_SUPPORTED_ATTRIBUTES,
+-  ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_SUBNET,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_BANNER = 28672,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_SAVE_PW,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_DEF_DOMAIN,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_SPLIT_DNS,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_SPLIT_INC,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_DO_PFS = 28679,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_FW_TYPE,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_BACKUP_SERVER,
+-  ISAKMP_MODECFG_ATTRIB_CISCO_DDNS_HOSTNAME,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_ADDRESS = 1,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NETMASK,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DNS,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NBNS,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_ADDRESS_EXPIRY,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DHCP,
++	ISAKMP_MODECFG_ATTRIB_APPLICATION_VERSION,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_ADDRESS,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_NETMASK,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_DNS,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_NBNS,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_DHCP,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_SUBNET,
++	ISAKMP_MODECFG_ATTRIB_SUPPORTED_ATTRIBUTES,
++	ISAKMP_MODECFG_ATTRIB_INTERNAL_IP6_SUBNET,
++	ISAKMP_MODECFG_ATTRIB_CISCO_BANNER = 28672,
++	ISAKMP_MODECFG_ATTRIB_CISCO_SAVE_PW,
++	ISAKMP_MODECFG_ATTRIB_CISCO_DEF_DOMAIN,
++	ISAKMP_MODECFG_ATTRIB_CISCO_SPLIT_DNS,
++	ISAKMP_MODECFG_ATTRIB_CISCO_SPLIT_INC,
++	ISAKMP_MODECFG_ATTRIB_CISCO_DO_PFS = 28679,
++	ISAKMP_MODECFG_ATTRIB_CISCO_FW_TYPE,
++	ISAKMP_MODECFG_ATTRIB_CISCO_BACKUP_SERVER,
++	ISAKMP_MODECFG_ATTRIB_CISCO_DDNS_HOSTNAME,
+ };
++
++#endif
+diff -Nurd vpnc-0.2-rm+zomb.1/isakmp-pkt.c new/isakmp-pkt.c
+--- vpnc-0.2-rm+zomb.1/isakmp-pkt.c	2003-11-11 21:46:39.000000000 +0100
++++ new/isakmp-pkt.c	2004-05-30 17:42:39.000000000 +0200
+@@ -22,404 +22,375 @@
+ #include <errno.h>
+ #include <stdio.h>
+ 
+-#include "isakmp-pkt.h"
+-#include "vpnc.h"
+ #include "sysdep.h"
++#include "config.h"
++#include "isakmp-pkt.h"
+ 
+-void *
+-xallocc (size_t x)
++void *xallocc(size_t x)
+ {
+-  void *result;
+-  result = calloc (1, x);
+-  if (result == NULL)
+-    error (1, errno, "malloc of %lu bytes failed", (unsigned long) x);
+-  return result;
++	void *result;
++	result = calloc(1, x);
++	if (result == NULL)
++		error(1, errno, "malloc of %lu bytes failed", (unsigned long)x);
++	return result;
+ }
+ 
+ struct flow {
+-  size_t len;
+-  uint8_t *base;
+-  uint8_t *end;
++	size_t len;
++	uint8_t *base;
++	uint8_t *end;
+ };
+ 
+-static uint8_t *
+-flow_reserve_p (struct flow *f, size_t sz)
++static uint8_t *flow_reserve_p(struct flow *f, size_t sz)
+ {
+-  size_t l = f->end - f->base;
+-  if (l + sz > f->len)
+-    {
+-      size_t new_len = f->len == 0 ? 128 : f->len;
+-      while (l + sz >= new_len)
+-	new_len *= 2;
++	size_t l = f->end - f->base;
++	if (l + sz > f->len) {
++		size_t new_len = f->len == 0 ? 128 : f->len;
++		while (l + sz >= new_len)
++			new_len *= 2;
+ 
+-      if (f->base == NULL)
+-	f->base = malloc (new_len);
+-      else
+-	f->base = realloc (f->base, new_len);
+-      if (f->base == NULL)
+-	error (1, errno, "alloc of %lud bytes failed", 
+-	       (unsigned long) new_len);
+-      memset (f->base + f->len, 0, new_len - f->len);
+-      f->end = f->base + l;
+-      f->len = new_len;
+-    }
+-  f->end += sz;
+-  return f->end - sz;
++		if (f->base == NULL)
++			f->base = malloc(new_len);
++		else
++			f->base = realloc(f->base, new_len);
++		if (f->base == NULL)
++			error(1, errno, "alloc of %lud bytes failed", (unsigned long)new_len);
++		memset(f->base + f->len, 0, new_len - f->len);
++		f->end = f->base + l;
++		f->len = new_len;
++	}
++	f->end += sz;
++	return f->end - sz;
+ }
+ 
+-static size_t
+-flow_reserve (struct flow *f, size_t sz)
++static size_t flow_reserve(struct flow *f, size_t sz)
+ {
+-  uint8_t *p = flow_reserve_p (f, sz);
+-  return p - f->base;
++	uint8_t *p = flow_reserve_p(f, sz);
++	return p - f->base;
+ }
+ 
+-static void
+-flow_x (struct flow *f, uint8_t *data, size_t data_len)
++static void flow_x(struct flow *f, uint8_t * data, size_t data_len)
+ {
+-  memcpy (flow_reserve_p (f, data_len), data, data_len);
++	memcpy(flow_reserve_p(f, data_len), data, data_len);
+ }
+ 
+-static void 
+-flow_1 (struct flow *f, uint8_t d)
++static void flow_1(struct flow *f, uint8_t d)
+ {
+-  flow_reserve_p (f, 1)[0] = d;
++	flow_reserve_p(f, 1)[0] = d;
+ }
+ 
+-static void 
+-flow_2 (struct flow *f, uint16_t d)
++static void flow_2(struct flow *f, uint16_t d)
+ {
+-  uint8_t dd[2];
+-  dd[0] = d >> 8;
+-  dd[1] = d;
+-  flow_x (f, dd, sizeof (dd));
++	uint8_t dd[2];
++	dd[0] = d >> 8;
++	dd[1] = d;
++	flow_x(f, dd, sizeof(dd));
+ }
+ 
+-static void 
+-flow_4 (struct flow *f, uint32_t d)
++static void flow_4(struct flow *f, uint32_t d)
+ {
+-  uint8_t dd[4];
+-  dd[0] = d >> 24;
+-  dd[1] = d >> 16;
+-  dd[2] = d >> 8;
+-  dd[3] = d;
+-  flow_x (f, dd, sizeof (dd));
++	uint8_t dd[4];
++	dd[0] = d >> 24;
++	dd[1] = d >> 16;
++	dd[2] = d >> 8;
++	dd[3] = d;
++	flow_x(f, dd, sizeof(dd));
+ }
+ 
+-static void
+-init_flow (struct flow *f)
++static void init_flow(struct flow *f)
+ {
+-  memset (f, 0, sizeof (*f));
++	memset(f, 0, sizeof(*f));
+ }
+ 
+-static void
+-flow_attribute (struct flow *f, struct isakmp_attribute *p)
++static void flow_attribute(struct flow *f, struct isakmp_attribute *p)
+ {
+-  for (; p; p = p->next)
+-    switch (p->af)
+-      {
+-      case isakmp_attr_lots:
+-	flow_2 (f, p->type);
+-	flow_2 (f, p->u.lots.length);
+-	flow_x (f, p->u.lots.data, p->u.lots.length);
+-	break;
+-      case isakmp_attr_16:
+-	flow_2 (f, p->type | 0x8000);
+-	flow_2 (f, p->u.attr_16);
+-	break;
+-      case isakmp_attr_2x8:
+-	flow_2 (f, p->type | 0x8000);
+-	flow_x (f, p->u.attr_2x8, 2);
+-	break;
+-      default:
+-	abort ();
+-      }
++	for (; p; p = p->next)
++		switch (p->af) {
++		case isakmp_attr_lots:
++			flow_2(f, p->type);
++			flow_2(f, p->u.lots.length);
++			flow_x(f, p->u.lots.data, p->u.lots.length);
++			break;
++		case isakmp_attr_16:
++			flow_2(f, p->type | 0x8000);
++			flow_2(f, p->u.attr_16);
++			break;
++		case isakmp_attr_2x8:
++			flow_2(f, p->type | 0x8000);
++			flow_x(f, p->u.attr_2x8, 2);
++			break;
++		default:
++			abort();
++		}
+ }
+ 
+-static void
+-flow_payload (struct flow *f, struct isakmp_payload *p)
++static void flow_payload(struct flow *f, struct isakmp_payload *p)
+ {
+-  size_t lpos;
+-  size_t baselen;
+-  
+-  if (p == NULL)
+-    return;
++	size_t lpos;
++	size_t baselen;
+ 
+-  baselen = f->end - f->base;
+-  if (p->next == NULL)
+-    flow_1 (f, 0);
+-  else
+-    flow_1 (f, p->next->type);
+-  flow_1 (f, 0);
+-  lpos = flow_reserve (f, 2);
+-  switch (p->type)
+-    {
+-    case ISAKMP_PAYLOAD_SA:
+-      flow_4 (f, p->u.sa.doi);
+-      flow_4 (f, p->u.sa.situation);
+-      flow_payload (f, p->u.sa.proposals);
+-      break;
+-    case ISAKMP_PAYLOAD_P:
+-      flow_1 (f, p->u.p.number);
+-      flow_1 (f, p->u.p.prot_id);
+-      flow_1 (f, p->u.p.spi_size);
+-      {
+-	uint8_t num_xform = 0;
+-	struct isakmp_payload *xform;
+-	for (xform = p->u.p.transforms; xform; xform = xform->next)
+-	  num_xform++;
+-	flow_1 (f, num_xform);
+-      }
+-      flow_x (f, p->u.p.spi, p->u.p.spi_size);
+-      flow_payload (f, p->u.p.transforms);
+-      break;
+-    case ISAKMP_PAYLOAD_T:
+-      flow_1 (f, p->u.t.number);
+-      flow_1 (f, p->u.t.id);
+-      flow_2 (f, 0);
+-      flow_attribute (f, p->u.t.attributes);
+-      break;
+-    case ISAKMP_PAYLOAD_KE:
+-    case ISAKMP_PAYLOAD_HASH:
+-    case ISAKMP_PAYLOAD_SIG:
+-    case ISAKMP_PAYLOAD_NONCE:
+-    case ISAKMP_PAYLOAD_VID:
+-      flow_x (f, p->u.ke.data, p->u.ke.length);
+-      break;
+-    case ISAKMP_PAYLOAD_ID:
+-      flow_1 (f, p->u.id.type);
+-      flow_1 (f, p->u.id.protocol);
+-      flow_2 (f, p->u.id.port);
+-      flow_x (f, p->u.id.data, p->u.id.length);
+-      break;
+-    case ISAKMP_PAYLOAD_CERT:
+-    case ISAKMP_PAYLOAD_CR:
+-      flow_1 (f, p->u.cert.encoding);
+-      flow_x (f, p->u.cert.data, p->u.cert.length);
+-      break;
+-    case ISAKMP_PAYLOAD_N:
+-      flow_4 (f, p->u.n.doi);
+-      flow_1 (f, p->u.n.protocol);
+-      flow_1 (f, p->u.n.spi_length);
+-      flow_2 (f, p->u.n.type);
+-      flow_x (f, p->u.n.spi, p->u.n.spi_length);
+-      flow_x (f, p->u.n.data, p->u.n.data_length);
+-      break;
+-    case ISAKMP_PAYLOAD_D:
+-      flow_4 (f, p->u.d.doi);
+-      flow_1 (f, p->u.d.protocol);
+-      flow_1 (f, p->u.d.spi_length);
+-      flow_2 (f, p->u.d.num_spi);
+-      if (p->u.d.spi_length > 0)
+-	{
+-	  int i;
+-	  for (i = 0; i < p->u.d.num_spi; i++)
+-	    flow_x (f, p->u.d.spi[i], p->u.d.spi_length);
++	if (p == NULL)
++		return;
++
++	baselen = f->end - f->base;
++	if (p->next == NULL)
++		flow_1(f, 0);
++	else
++		flow_1(f, p->next->type);
++	flow_1(f, 0);
++	lpos = flow_reserve(f, 2);
++	switch (p->type) {
++	case ISAKMP_PAYLOAD_SA:
++		flow_4(f, p->u.sa.doi);
++		flow_4(f, p->u.sa.situation);
++		flow_payload(f, p->u.sa.proposals);
++		break;
++	case ISAKMP_PAYLOAD_P:
++		flow_1(f, p->u.p.number);
++		flow_1(f, p->u.p.prot_id);
++		flow_1(f, p->u.p.spi_size);
++		{
++			uint8_t num_xform = 0;
++			struct isakmp_payload *xform;
++			for (xform = p->u.p.transforms; xform; xform = xform->next)
++				num_xform++;
++			flow_1(f, num_xform);
++		}
++		flow_x(f, p->u.p.spi, p->u.p.spi_size);
++		flow_payload(f, p->u.p.transforms);
++		break;
++	case ISAKMP_PAYLOAD_T:
++		flow_1(f, p->u.t.number);
++		flow_1(f, p->u.t.id);
++		flow_2(f, 0);
++		flow_attribute(f, p->u.t.attributes);
++		break;
++	case ISAKMP_PAYLOAD_KE:
++	case ISAKMP_PAYLOAD_HASH:
++	case ISAKMP_PAYLOAD_SIG:
++	case ISAKMP_PAYLOAD_NONCE:
++	case ISAKMP_PAYLOAD_VID:
++		flow_x(f, p->u.ke.data, p->u.ke.length);
++		break;
++	case ISAKMP_PAYLOAD_ID:
++		flow_1(f, p->u.id.type);
++		flow_1(f, p->u.id.protocol);
++		flow_2(f, p->u.id.port);
++		flow_x(f, p->u.id.data, p->u.id.length);
++		break;
++	case ISAKMP_PAYLOAD_CERT:
++	case ISAKMP_PAYLOAD_CR:
++		flow_1(f, p->u.cert.encoding);
++		flow_x(f, p->u.cert.data, p->u.cert.length);
++		break;
++	case ISAKMP_PAYLOAD_N:
++		flow_4(f, p->u.n.doi);
++		flow_1(f, p->u.n.protocol);
++		flow_1(f, p->u.n.spi_length);
++		flow_2(f, p->u.n.type);
++		flow_x(f, p->u.n.spi, p->u.n.spi_length);
++		flow_x(f, p->u.n.data, p->u.n.data_length);
++		break;
++	case ISAKMP_PAYLOAD_D:
++		flow_4(f, p->u.d.doi);
++		flow_1(f, p->u.d.protocol);
++		flow_1(f, p->u.d.spi_length);
++		flow_2(f, p->u.d.num_spi);
++		if (p->u.d.spi_length > 0) {
++			int i;
++			for (i = 0; i < p->u.d.num_spi; i++)
++				flow_x(f, p->u.d.spi[i], p->u.d.spi_length);
++		}
++		break;
++	case ISAKMP_PAYLOAD_MODECFG_ATTR:
++		flow_1(f, p->u.modecfg.type);
++		flow_1(f, 0);
++		flow_2(f, p->u.modecfg.id);
++		flow_attribute(f, p->u.modecfg.attributes);
++		break;
++	default:
++		abort();
+ 	}
+-      break;
+-    case ISAKMP_PAYLOAD_MODECFG_ATTR:
+-      flow_1 (f, p->u.modecfg.type);
+-      flow_1 (f, 0);
+-      flow_2 (f, p->u.modecfg.id);
+-      flow_attribute (f, p->u.modecfg.attributes);
+-      break;
+-    default:
+-      abort ();
+-    }
+-  f->base[lpos] = (f->end - f->base - baselen) >> 8;
+-  f->base[lpos + 1] = (f->end - f->base - baselen);
+-  flow_payload (f, p->next);
++	f->base[lpos] = (f->end - f->base - baselen) >> 8;
++	f->base[lpos + 1] = (f->end - f->base - baselen);
++	flow_payload(f, p->next);
+ }
+ 
+-void flatten_isakmp_payload (struct isakmp_payload *p, 
+-			     uint8_t **result, size_t *size)
++void flatten_isakmp_payload(struct isakmp_payload *p, uint8_t ** result, size_t * size)
+ {
+-  struct flow f;
+-  init_flow (&f);
+-  flow_payload (&f, p);
+-  *result = f.base;
+-  *size = f.end - f.base;
++	struct flow f;
++	init_flow(&f);
++	flow_payload(&f, p);
++	*result = f.base;
++	*size = f.end - f.base;
+ }
+ 
+-void flatten_isakmp_packet (struct isakmp_packet *p, 
+-			    uint8_t **result, size_t *size, size_t blksz)
++void flatten_isakmp_packet(struct isakmp_packet *p, uint8_t ** result, size_t * size, size_t blksz)
+ {
+-  struct flow f;
+-  size_t lpos, sz, padding;
+-  
+-  init_flow (&f);
+-  flow_x (&f, p->i_cookie, ISAKMP_COOKIE_LENGTH);
+-  flow_x (&f, p->r_cookie, ISAKMP_COOKIE_LENGTH);
+-  if (p->payload == NULL)
+-    flow_1 (&f, 0);
+-  else
+-    flow_1 (&f, p->payload->type);
+-  flow_1 (&f, p->isakmp_version);
+-  flow_1 (&f, p->exchange_type);
+-  flow_1 (&f, p->flags);
+-  flow_4 (&f, p->message_id);
+-  lpos = flow_reserve (&f, 4);
+-  flow_payload (&f, p->payload);
+-  if (p->flags & ISAKMP_FLAG_E) {
+-    assert(blksz != 0);
+-    sz = (f.end - f.base) - ISAKMP_PAYLOAD_O;
+-    padding = blksz - (sz % blksz);
+-    if (padding == blksz)
+-      padding = 0;
+-    DEBUG(3, printf("size = %ld, blksz = %ld, padding = %ld\n",
+-	(long)sz, (long)blksz, (long)padding));
+-    flow_reserve (&f, padding);
+-  }
+-  f.base[lpos] = (f.end - f.base) >> 24;
+-  f.base[lpos+1] = (f.end - f.base) >> 16;
+-  f.base[lpos+2] = (f.end - f.base) >> 8;
+-  f.base[lpos+3] = (f.end - f.base);
+-  *result = f.base;
+-  *size = f.end - f.base;
+-/*DUMP*/
+-  if (opt_debug >= 3) {
+-    printf("\n sending: ========================>\n");
+-    free_isakmp_packet(parse_isakmp_packet(f.base, f.end - f.base, NULL));
+-  }
++	struct flow f;
++	size_t lpos, sz, padding;
++
++	init_flow(&f);
++	flow_x(&f, p->i_cookie, ISAKMP_COOKIE_LENGTH);
++	flow_x(&f, p->r_cookie, ISAKMP_COOKIE_LENGTH);
++	if (p->payload == NULL)
++		flow_1(&f, 0);
++	else
++		flow_1(&f, p->payload->type);
++	flow_1(&f, p->isakmp_version);
++	flow_1(&f, p->exchange_type);
++	flow_1(&f, p->flags);
++	flow_4(&f, p->message_id);
++	lpos = flow_reserve(&f, 4);
++	flow_payload(&f, p->payload);
++	if (p->flags & ISAKMP_FLAG_E) {
++		assert(blksz != 0);
++		sz = (f.end - f.base) - ISAKMP_PAYLOAD_O;
++		padding = blksz - (sz % blksz);
++		if (padding == blksz)
++			padding = 0;
++		DEBUG(3, printf("size = %ld, blksz = %ld, padding = %ld\n",
++				(long)sz, (long)blksz, (long)padding));
++		flow_reserve(&f, padding);
++	}
++	f.base[lpos] = (f.end - f.base) >> 24;
++	f.base[lpos + 1] = (f.end - f.base) >> 16;
++	f.base[lpos + 2] = (f.end - f.base) >> 8;
++	f.base[lpos + 3] = (f.end - f.base);
++	*result = f.base;
++	*size = f.end - f.base;
++	 /*DUMP*/ if (opt_debug >= 3) {
++		printf("\n sending: ========================>\n");
++		free_isakmp_packet(parse_isakmp_packet(f.base, f.end - f.base, NULL));
++	}
+ }
+ 
+-struct isakmp_attribute * 
+-new_isakmp_attribute(uint16_t type, struct isakmp_attribute *next)
++struct isakmp_attribute *new_isakmp_attribute(uint16_t type, struct isakmp_attribute *next)
+ {
+-  struct isakmp_attribute *r = xallocc (sizeof (struct isakmp_attribute));
+-  r->type = type;
+-  r->next = next;
+-  return r;
++	struct isakmp_attribute *r = xallocc(sizeof(struct isakmp_attribute));
++	r->type = type;
++	r->next = next;
++	return r;
+ }
+ 
+-struct isakmp_attribute * 
+-new_isakmp_attribute_16(uint16_t type, uint16_t data, 
+-			struct isakmp_attribute *next)
++struct isakmp_attribute *new_isakmp_attribute_16(uint16_t type, uint16_t data,
++	struct isakmp_attribute *next)
+ {
+-  struct isakmp_attribute *r = xallocc (sizeof (struct isakmp_attribute));
+-  r->next = next;
+-  r->type = type;
+-  r->af = isakmp_attr_16;
+-  r->u.attr_16 = data;
+-  return r;
++	struct isakmp_attribute *r = xallocc(sizeof(struct isakmp_attribute));
++	r->next = next;
++	r->type = type;
++	r->af = isakmp_attr_16;
++	r->u.attr_16 = data;
++	return r;
+ }
+ 
+-struct isakmp_packet * 
+-new_isakmp_packet(void)
++struct isakmp_packet *new_isakmp_packet(void)
+ {
+-  return xallocc (sizeof (struct isakmp_packet));
++	return xallocc(sizeof(struct isakmp_packet));
+ }
+ 
+-struct isakmp_payload * 
+-new_isakmp_payload(uint8_t type)
++struct isakmp_payload *new_isakmp_payload(uint8_t type)
+ {
+-  struct isakmp_payload *result = xallocc (sizeof (struct isakmp_packet));
+-  result->type = type;
+-  return result;
++	struct isakmp_payload *result = xallocc(sizeof(struct isakmp_packet));
++	result->type = type;
++	return result;
+ }
+ 
+-struct isakmp_payload * 
+-new_isakmp_data_payload(uint8_t type, const void *data, size_t data_length)
++struct isakmp_payload *new_isakmp_data_payload(uint8_t type, const void *data, size_t data_length)
+ {
+-  struct isakmp_payload *result = xallocc (sizeof (struct isakmp_packet));
+-  
+-  if (type != ISAKMP_PAYLOAD_KE && type != ISAKMP_PAYLOAD_HASH
+-      && type != ISAKMP_PAYLOAD_SIG && type != ISAKMP_PAYLOAD_NONCE
+-      && type != ISAKMP_PAYLOAD_VID)
+-    abort ();
+-  if (data_length >= 16384)
+-    abort ();
++	struct isakmp_payload *result = xallocc(sizeof(struct isakmp_packet));
+ 
+-  result->type = type;
+-  result->u.ke.length = data_length;
+-  result->u.ke.data = xallocc (data_length);
+-  memcpy (result->u.ke.data, data, data_length);
+-  return result;
++	if (type != ISAKMP_PAYLOAD_KE && type != ISAKMP_PAYLOAD_HASH
++		&& type != ISAKMP_PAYLOAD_SIG && type != ISAKMP_PAYLOAD_NONCE
++		&& type != ISAKMP_PAYLOAD_VID)
++		abort();
++	if (data_length >= 16384)
++		abort();
++
++	result->type = type;
++	result->u.ke.length = data_length;
++	result->u.ke.data = xallocc(data_length);
++	memcpy(result->u.ke.data, data, data_length);
++	return result;
+ }
+ 
+-void
+-free_isakmp_payload(struct isakmp_payload *p)
++void free_isakmp_payload(struct isakmp_payload *p)
+ {
+-  struct isakmp_payload *nxt;
+-  
+-  if (p == NULL)
+-    return;
+-  
+-  switch (p->type)
+-    {
+-     case ISAKMP_PAYLOAD_SA:
+-      free_isakmp_payload (p->u.sa.proposals);
+-      break;
+-    case ISAKMP_PAYLOAD_P:
+-      free_isakmp_payload (p->u.p.transforms);
+-      break;
+-    case ISAKMP_PAYLOAD_T:
+-      {
+-	struct isakmp_attribute *att, *natt;
+-	for (att = p->u.t.attributes; att; att = natt)
+-	  {
+-	    natt = att->next;
+-	    if (att->af == isakmp_attr_lots)
+-	      free (att->u.lots.data);
+-	    free (att);
+-	  }
+-      }
+-      break;
+-    case ISAKMP_PAYLOAD_KE:
+-    case ISAKMP_PAYLOAD_HASH:
+-    case ISAKMP_PAYLOAD_SIG:
+-    case ISAKMP_PAYLOAD_NONCE:
+-    case ISAKMP_PAYLOAD_VID:
+-      free (p->u.ke.data);
+-      break;
+-    case ISAKMP_PAYLOAD_ID:
+-      free (p->u.id.data);
+-      break;
+-    case ISAKMP_PAYLOAD_CERT:
+-    case ISAKMP_PAYLOAD_CR:
+-      free (p->u.cert.data);
+-      break;
+-    case ISAKMP_PAYLOAD_N:
+-      free (p->u.n.spi);
+-      free (p->u.n.data);
+-      break;
+-    case ISAKMP_PAYLOAD_D:
+-      if (p->u.d.spi)
+-	{
+-	  int i;
+-	  for (i = 0; i < p->u.d.num_spi; i++)
+-	    free (p->u.d.spi[i]);
+-	  free (p->u.d.spi);
++	struct isakmp_payload *nxt;
++
++	if (p == NULL)
++		return;
++
++	switch (p->type) {
++	case ISAKMP_PAYLOAD_SA:
++		free_isakmp_payload(p->u.sa.proposals);
++		break;
++	case ISAKMP_PAYLOAD_P:
++		free_isakmp_payload(p->u.p.transforms);
++		break;
++	case ISAKMP_PAYLOAD_T:
++		{
++			struct isakmp_attribute *att, *natt;
++			for (att = p->u.t.attributes; att; att = natt) {
++				natt = att->next;
++				if (att->af == isakmp_attr_lots)
++					free(att->u.lots.data);
++				free(att);
++			}
++		}
++		break;
++	case ISAKMP_PAYLOAD_KE:
++	case ISAKMP_PAYLOAD_HASH:
++	case ISAKMP_PAYLOAD_SIG:
++	case ISAKMP_PAYLOAD_NONCE:
++	case ISAKMP_PAYLOAD_VID:
++		free(p->u.ke.data);
++		break;
++	case ISAKMP_PAYLOAD_ID:
++		free(p->u.id.data);
++		break;
++	case ISAKMP_PAYLOAD_CERT:
++	case ISAKMP_PAYLOAD_CR:
++		free(p->u.cert.data);
++		break;
++	case ISAKMP_PAYLOAD_N:
++		free(p->u.n.spi);
++		free(p->u.n.data);
++		break;
++	case ISAKMP_PAYLOAD_D:
++		if (p->u.d.spi) {
++			int i;
++			for (i = 0; i < p->u.d.num_spi; i++)
++				free(p->u.d.spi[i]);
++			free(p->u.d.spi);
++		}
++		break;
++	case ISAKMP_PAYLOAD_MODECFG_ATTR:
++		{
++			struct isakmp_attribute *att, *natt;
++			for (att = p->u.modecfg.attributes; att; att = natt) {
++				natt = att->next;
++				if (att->af == isakmp_attr_lots)
++					free(att->u.lots.data);
++				free(att);
++			}
++		}
++		break;
++	default:
++		abort();
++
+ 	}
+-      break;
+-    case ISAKMP_PAYLOAD_MODECFG_ATTR:
+-      {
+-	struct isakmp_attribute *att, *natt;
+-	for (att = p->u.modecfg.attributes; att; att = natt)
+-	  {
+-	    natt = att->next;
+-	    if (att->af == isakmp_attr_lots)
+-	      free (att->u.lots.data);
+-	    free (att);
+-	  }
+-      }
+-      break;
+-    default:
+-      abort ();
+-     
+-    }
+-  nxt = p->next;
+-  free (p);
+-  free_isakmp_payload (nxt);
++	nxt = p->next;
++	free(p);
++	free_isakmp_payload(nxt);
+ }
+ 
+-void
+-free_isakmp_packet(struct isakmp_packet *p)
++void free_isakmp_packet(struct isakmp_packet *p)
+ {
+-  if (p == NULL)
+-    return;
+-  free_isakmp_payload (p->payload);
+-  free (p);
++	if (p == NULL)
++		return;
++	free_isakmp_payload(p->payload);
++	free(p);
+ }
+ 
+ #define fetch4()  					\
+@@ -433,448 +404,422 @@
+ #define fetchn(d,n)  \
+   (memcpy ((d), data, (n)), data += (n), data_len -= (n))
+ 
+-static struct isakmp_attribute *
+-parse_isakmp_attributes (const uint8_t **data_p, 
+-			 size_t data_len, uint16_t *reject)
++static struct isakmp_attribute *parse_isakmp_attributes(const uint8_t ** data_p,
++	size_t data_len, uint16_t * reject)
+ {
+-  const uint8_t *data = *data_p;
+-  struct isakmp_attribute *r;
+-  uint16_t type, length;
+-  
+-  if (data_len < 4)
+-    return NULL;
+-  
+-  r = new_isakmp_attribute (0, NULL);
+-  type = fetch2();
+-  length = fetch2();
+-  if (type & 0x8000)
+-    {
+-      r->type = type & ~0x8000;
+-hex_dump("t.attributes.type", &r->type, 2);
+-      r->af = isakmp_attr_16;
+-      r->u.attr_16 = length;
+-if ((ISAKMP_XAUTH_ATTRIB_TYPE <=r->type)&&(r->type<= ISAKMP_XAUTH_ATTRIB_ANSWER)&&(opt_debug < 99))
+-		DEBUG(3,printf("(not dumping xauth data)\n"));
+-	else
+-		hex_dump("t.attributes.u.attr_16", &r->u.attr_16, 2);
+-    }
+-  else
+-    {
+-      r->type = type;
+-hex_dump("t.attributes.type", &r->type, 2);
+-      r->af = isakmp_attr_lots;
+-      r->u.lots.length = length;
+-if ((ISAKMP_XAUTH_ATTRIB_TYPE <=r->type)&&(r->type<= ISAKMP_XAUTH_ATTRIB_ANSWER)&&(opt_debug < 99))
+-		DEBUG(3,printf("(not dumping xauth data length)\n"));
+-	else
+-		hex_dump("t.attributes.u.lots.length", &r->u.lots.length, 2);
+-      if (data_len < length)
+-	{
+-	  *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-	  return r;
++	const uint8_t *data = *data_p;
++	struct isakmp_attribute *r;
++	uint16_t type, length;
++
++	if (data_len < 4)
++		return NULL;
++
++	r = new_isakmp_attribute(0, NULL);
++	type = fetch2();
++	length = fetch2();
++	if (type & 0x8000) {
++		r->type = type & ~0x8000;
++		hex_dump("t.attributes.type", &r->type, UINT16);
++		r->af = isakmp_attr_16;
++		r->u.attr_16 = length;
++		if ((ISAKMP_XAUTH_ATTRIB_TYPE <= r->type)
++			&& (r->type <= ISAKMP_XAUTH_ATTRIB_ANSWER)
++			&& (opt_debug < 99))
++			DEBUG(3, printf("(not dumping xauth data)\n"));
++		else
++			hex_dump("t.attributes.u.attr_16", &r->u.attr_16, UINT16);
++	} else {
++		r->type = type;
++		hex_dump("t.attributes.type", &r->type, UINT16);
++		r->af = isakmp_attr_lots;
++		r->u.lots.length = length;
++		if ((ISAKMP_XAUTH_ATTRIB_TYPE <= r->type) && (r->type <= ISAKMP_XAUTH_ATTRIB_ANSWER)
++			&& (opt_debug < 99))
++			DEBUG(3, printf("(not dumping xauth data length)\n"));
++		else
++			hex_dump("t.attributes.u.lots.length", &r->u.lots.length, UINT16);
++		if (data_len < length) {
++			*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++			return r;
++		}
++		r->u.lots.data = xallocc(length);
++		fetchn(r->u.lots.data, length);
++		if ((ISAKMP_XAUTH_ATTRIB_TYPE <= type) && (type <= ISAKMP_XAUTH_ATTRIB_ANSWER)
++			&& (opt_debug < 99))
++			DEBUG(3, printf("(not dumping xauth data)\n"));
++		else
++			hex_dump("t.attributes.u.lots.data", r->u.lots.data, r->u.lots.length);
+ 	}
+-      r->u.lots.data = xallocc (length);
+-      fetchn (r->u.lots.data, length);
+-if ((ISAKMP_XAUTH_ATTRIB_TYPE <= type)&&(type <= ISAKMP_XAUTH_ATTRIB_ANSWER)&&(opt_debug < 99))
+-		DEBUG(3,printf("(not dumping xauth data)\n"));
+-	else
+-		hex_dump("t.attributes.u.lots.data", r->u.lots.data, r->u.lots.length);
+-    }
+-  r->next = parse_isakmp_attributes (&data, data_len, reject);
+-  *data_p = data;
+-  return r;
++	r->next = parse_isakmp_attributes(&data, data_len, reject);
++	*data_p = data;
++	return r;
+ }
+ 
+-static struct isakmp_payload *
+-parse_isakmp_payload (uint8_t type,
+-		      const uint8_t **data_p, 
+-		      size_t * data_len_p, uint16_t *reject)
++static struct isakmp_payload *parse_isakmp_payload(uint8_t type,
++	const uint8_t ** data_p, size_t * data_len_p, uint16_t * reject)
+ {
+-  const uint8_t *data = *data_p;
+-  size_t data_len = *data_len_p;
+-  struct isakmp_payload *r;
+-  uint8_t next_type;
+-  size_t length, olength;
+-
+-  static const uint16_t min_payload_len[ISAKMP_PAYLOAD_MODECFG_ATTR + 1] = {
+-    4, 12, 8, 8, 4, 8, 5, 5, 4, 4, 4, 12, 12, 4, 8
+-  };
++	const uint8_t *data = *data_p;
++	size_t data_len = *data_len_p;
++	struct isakmp_payload *r;
++	uint8_t next_type;
++	size_t length, olength;
+ 
+-hex_dump("PARSING PAYLOAD type", &type, sizeof(type));
+-  if (type == 0)
+-    return NULL;
+-  if (type > ISAKMP_PAYLOAD_MODECFG_ATTR)
+-    {
+-      *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-      return NULL;
+-    }
+-  if (data_len < min_payload_len[type])
+-    {
+-      *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-      return NULL;
+-    }
++	static const uint16_t min_payload_len[ISAKMP_PAYLOAD_MODECFG_ATTR + 1] = {
++		4, 12, 8, 8, 4, 8, 5, 5, 4, 4, 4, 12, 12, 4, 8
++	};
+ 
+-  r = new_isakmp_payload (type);
+-  next_type = fetch1();
+-hex_dump("next_type", &next_type, sizeof(next_type));
+-  if (fetch1() != 0)
+-    {
+-      *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-      return r;
+-    }
+-  length = fetch2();
+-hex_dump("length", &length, sizeof(length));
+-  if (length > data_len + 4 || length < min_payload_len[type])
+-    {
+-      *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-      return r;
+-    }
+-  olength = length;
+-  switch (type)
+-    {
+-    case ISAKMP_PAYLOAD_SA:
+-      r->u.sa.doi = fetch4();
+-hex_dump("sa.doi", &r->u.sa.doi, sizeof(r->u.sa.doi));
+-      if (r->u.sa.doi != ISAKMP_DOI_IPSEC)
+-	{
+-	  *reject = ISAKMP_N_DOI_NOT_SUPPORTED;
+-	  return r;
++	hex_dump("PARSING PAYLOAD type", &type, UINT8);
++	if (type == 0)
++		return NULL;
++	if (type > ISAKMP_PAYLOAD_MODECFG_ATTR) {
++		*reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++		return NULL;
+ 	}
+-      r->u.sa.situation = fetch4();
+-hex_dump("sa.situation", &r->u.sa.situation, sizeof(r->u.sa.situation));
+-      if (r->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY)
+-	{
+-	  *reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
+-	  return r;
++	if (data_len < min_payload_len[type]) {
++		*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++		return NULL;
+ 	}
+-      *reject = 0;
+-      length -= 12;
+-      r->u.sa.proposals = parse_isakmp_payload (ISAKMP_PAYLOAD_P, 
+-						&data, &length, 
+-						reject);
+-      if (*reject != 0)
+-	return r;
+-      /* Allow trailing garbage at end of payload.  */
+-      data_len -= olength - 12;
+-     break;
+ 
+-    case ISAKMP_PAYLOAD_P:
+-      if (next_type != ISAKMP_PAYLOAD_P && next_type != 0)
+-	{
+-	  *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-	  return r;
++	r = new_isakmp_payload(type);
++	next_type = fetch1();
++	hex_dump("next_type", &next_type, UINT8);
++	if (fetch1() != 0) {
++		*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++		return r;
+ 	}
+-      {
+-	uint8_t num_xform;
+-	struct isakmp_payload *xform;
++	length = fetch2();
++	hex_dump("length", &length, UINT16);
++	if (length > data_len + 4 || length < min_payload_len[type]) {
++		*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++		return r;
++	}
++	olength = length;
++	switch (type) {
++	case ISAKMP_PAYLOAD_SA:
++		r->u.sa.doi = fetch4();
++		hex_dump("sa.doi", &r->u.sa.doi, UINT32);
++		if (r->u.sa.doi != ISAKMP_DOI_IPSEC) {
++			*reject = ISAKMP_N_DOI_NOT_SUPPORTED;
++			return r;
++		}
++		r->u.sa.situation = fetch4();
++		hex_dump("sa.situation", &r->u.sa.situation, UINT32);
++		if (r->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY) {
++			*reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
++			return r;
++		}
++		*reject = 0;
++		length -= 12;
++		r->u.sa.proposals = parse_isakmp_payload(ISAKMP_PAYLOAD_P, &data, &length, reject);
++		if (*reject != 0)
++			return r;
++		/* Allow trailing garbage at end of payload.  */
++		data_len -= olength - 12;
++		break;
+ 
+-	r->u.p.number = fetch1();
+-hex_dump("p.number", &r->u.p.number, sizeof(r->u.p.number));
+-	r->u.p.prot_id = fetch1();
+-hex_dump("p.prot_id", &r->u.p.prot_id, sizeof(r->u.p.prot_id));
+-	r->u.p.spi_size = fetch1();
+-hex_dump("p.spi_size", &r->u.p.spi_size, sizeof(r->u.p.spi_size));
+-	num_xform = fetch1();
+-hex_dump("length", &num_xform, sizeof(num_xform));
++	case ISAKMP_PAYLOAD_P:
++		if (next_type != ISAKMP_PAYLOAD_P && next_type != 0) {
++			*reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++			return r;
++		}
++		{
++			uint8_t num_xform;
++			struct isakmp_payload *xform;
+ 
+-	if (data_len < r->u.p.spi_size)
+-	  {
+-	    *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-	    return r;
+-	  }
+-	r->u.p.spi = xallocc (r->u.p.spi_size);
+-	fetchn (r->u.p.spi, r->u.p.spi_size);
+-hex_dump("p.spi", r->u.p.spi, r->u.p.spi_size);
+-	length -= 8 + r->u.p.spi_size;
+-	r->u.p.transforms = parse_isakmp_payload (ISAKMP_PAYLOAD_T, 
+-						  &data, &length, 
+-						  reject);
+-	for (xform = r->u.p.transforms; xform; xform = xform->next)
+-	  if (num_xform-- == 0)
+-	    break;
+-	if (num_xform != 0)
+-	    {
+-	      *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	      return r;
+-	    }
+-	
+-	/* Allow trailing garbage at end of payload.  */
+-	data_len -= olength - 8 - r->u.p.spi_size;
+-      }
+-      break;
++			r->u.p.number = fetch1();
++			hex_dump("p.number", &r->u.p.number, UINT8);
++			r->u.p.prot_id = fetch1();
++			hex_dump("p.prot_id", &r->u.p.prot_id, UINT8);
++			r->u.p.spi_size = fetch1();
++			hex_dump("p.spi_size", &r->u.p.spi_size, UINT8);
++			num_xform = fetch1();
++			hex_dump("length", &num_xform, UINT8);
+ 
+-    case ISAKMP_PAYLOAD_T:
+-      if (next_type != ISAKMP_PAYLOAD_T && next_type != 0)
+-	{
+-	  *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-	  return r;
+-	}
+-      r->u.t.number = fetch1();
+-hex_dump("t.number", &r->u.t.number, sizeof(r->u.t.number));
+-      r->u.t.id = fetch1();
+-hex_dump("t.id", &r->u.t.id, sizeof(r->u.t.id));
+-      if (fetch2() != 0)
+-	{
+-	  *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	  return r;
+-	}
+-      length -= 8;
+-      r->u.t.attributes = parse_isakmp_attributes (&data, length, reject);
+-      data_len -= olength - 8;
+-      break;
++			if (data_len < r->u.p.spi_size) {
++				*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++				return r;
++			}
++			r->u.p.spi = xallocc(r->u.p.spi_size);
++			fetchn(r->u.p.spi, r->u.p.spi_size);
++			hex_dump("p.spi", r->u.p.spi, r->u.p.spi_size);
++			length -= 8 + r->u.p.spi_size;
++			r->u.p.transforms = parse_isakmp_payload(ISAKMP_PAYLOAD_T,
++				&data, &length, reject);
++			for (xform = r->u.p.transforms; xform; xform = xform->next)
++				if (num_xform-- == 0)
++					break;
++			if (num_xform != 0) {
++				*reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++				return r;
++			}
+ 
+-    case ISAKMP_PAYLOAD_KE:
+-    case ISAKMP_PAYLOAD_HASH:
+-    case ISAKMP_PAYLOAD_SIG:
+-    case ISAKMP_PAYLOAD_NONCE:
+-    case ISAKMP_PAYLOAD_VID:
+-      r->u.ke.length = length - 4;
+-      r->u.ke.data = xallocc (r->u.ke.length);
+-      fetchn (r->u.ke.data, r->u.ke.length);
+-hex_dump("ke.data", r->u.ke.data, r->u.ke.length);
+-      break;
+-    case ISAKMP_PAYLOAD_ID:
+-      r->u.id.type = fetch1();
+-hex_dump("id.type", &r->u.id.type, sizeof(r->u.id.type));
+-      r->u.id.protocol = fetch1();
+-hex_dump("id.protocol", &r->u.id.protocol, sizeof(r->u.id.protocol));
+-      r->u.id.port = fetch2();
+-hex_dump("id.port", &r->u.id.port, sizeof(r->u.id.port));
+-      r->u.id.length = length - 8;
+-      r->u.id.data = xallocc (r->u.id.length);
+-      fetchn (r->u.id.data, r->u.id.length);
+-hex_dump("id.data", r->u.id.data, r->u.id.length);
+-      break;
+-    case ISAKMP_PAYLOAD_CERT:
+-    case ISAKMP_PAYLOAD_CR:
+-      r->u.cert.encoding = fetch1();
+-hex_dump("cert.encoding", &r->u.cert.encoding, 1);
+-      r->u.cert.length = length - 5;
+-      fetchn (r->u.cert.data, r->u.cert.length);
+-hex_dump("cert.data", r->u.cert.data, r->u.cert.length);
+-      break;
+-    case ISAKMP_PAYLOAD_N:
+-      r->u.n.doi = fetch4();
+-hex_dump("n.doi", &r->u.n.doi, 4);
+-      r->u.n.protocol = fetch1();
+-hex_dump("n.protocol", &r->u.n.protocol, 1);
+-      r->u.n.spi_length = fetch1();
+-hex_dump("n.spi_length", &r->u.n.spi_length, 1);
+-      r->u.n.type = fetch2();
+-hex_dump("n.type", &r->u.n.type, 2);
+-      if (r->u.n.spi_length + 12u > length)
+-	{
+-	  *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-	  return r;
+-	}
+-      r->u.n.spi = xallocc (r->u.n.spi_length);
+-      fetchn (r->u.n.spi, r->u.n.spi_length);
+-hex_dump("n.spi", r->u.n.spi, r->u.n.spi_length);
+-      r->u.n.data_length = length - 12 - r->u.n.spi_length;
+-      r->u.n.data = xallocc (r->u.n.data_length);
+-      fetchn (r->u.n.data, r->u.n.data_length);
+-hex_dump("n.data", r->u.n.data, r->u.n.data_length);
+-      break;
+-    case ISAKMP_PAYLOAD_D:
+-      r->u.n.doi = fetch4();
+-hex_dump("n.doi", &r->u.n.doi, 1);
+-      r->u.n.protocol = fetch1();
+-hex_dump("n.protocol", &r->u.n.protocol, 1);
+-      r->u.n.spi_length = fetch1();
+-hex_dump("n.spi_length", &r->u.n.spi_length, 1);
+-      r->u.d.num_spi = fetch2();
+-hex_dump("d.num_spi", &r->u.d.num_spi, 2);
+-      if (r->u.d.num_spi * r->u.n.spi_length + 12u != length)
+-	{
+-	  *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-	  return r;
+-	}
+-      r->u.d.spi = xallocc (sizeof (uint8_t *) * r->u.d.num_spi);
+-      {
+-	int i;
+-	for (i = 0; i < r->u.d.num_spi; i++)
+-	  {
+-	    r->u.d.spi[i] = xallocc (r->u.d.spi_length);
+-	    fetchn (r->u.d.spi[i], r->u.d.spi_length);
+-hex_dump("d.spi", r->u.d.spi[i], r->u.d.spi_length);
+-	  }
+-      }
+-      break;
+-    case ISAKMP_PAYLOAD_MODECFG_ATTR:
+-      r->u.modecfg.type = fetch1();
+-hex_dump("modecfg.type", &r->u.modecfg.type, 1);
+-      if (fetch1() != 0)
+-	{
+-	  *reject = ISAKMP_N_PAYLOAD_MALFORMED;
+-	  return r;
+-	}
+-      r->u.t.id = fetch2();
+-hex_dump("t.id", &r->u.t.id, 2);
+-      length -= 8;
+-      r->u.t.attributes = parse_isakmp_attributes (&data, length, reject);
+-      data_len -= olength - 8;
+-      break;
++			/* Allow trailing garbage at end of payload.  */
++			data_len -= olength - 8 - r->u.p.spi_size;
++		}
++		break;
+ 
+-    default:
+-      abort ();
+-    }
+-  *data_p = data;
+-  *data_len_p = data_len;
+-hex_dump("DONE PARSING PAYLOAD type", &type, sizeof(type));
+-  r->next = parse_isakmp_payload (next_type, data_p, data_len_p, reject);
+-  return r;
++	case ISAKMP_PAYLOAD_T:
++		if (next_type != ISAKMP_PAYLOAD_T && next_type != 0) {
++			*reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++			return r;
++		}
++		r->u.t.number = fetch1();
++		hex_dump("t.number", &r->u.t.number, UINT8);
++		r->u.t.id = fetch1();
++		hex_dump("t.id", &r->u.t.id, UINT8);
++		if (fetch2() != 0) {
++			*reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++			return r;
++		}
++		length -= 8;
++		r->u.t.attributes = parse_isakmp_attributes(&data, length, reject);
++		data_len -= olength - 8;
++		break;
++
++	case ISAKMP_PAYLOAD_KE:
++	case ISAKMP_PAYLOAD_HASH:
++	case ISAKMP_PAYLOAD_SIG:
++	case ISAKMP_PAYLOAD_NONCE:
++	case ISAKMP_PAYLOAD_VID:
++		r->u.ke.length = length - 4;
++		r->u.ke.data = xallocc(r->u.ke.length);
++		fetchn(r->u.ke.data, r->u.ke.length);
++		hex_dump("ke.data", r->u.ke.data, r->u.ke.length);
++		break;
++	case ISAKMP_PAYLOAD_ID:
++		r->u.id.type = fetch1();
++		hex_dump("id.type", &r->u.id.type, UINT8);
++		r->u.id.protocol = fetch1();
++		hex_dump("id.protocol", &r->u.id.protocol, UINT8);
++		r->u.id.port = fetch2();
++		hex_dump("id.port", &r->u.id.port, sizeof(r->u.id.port));
++		r->u.id.length = length - 8;
++		r->u.id.data = xallocc(r->u.id.length);
++		fetchn(r->u.id.data, r->u.id.length);
++		hex_dump("id.data", r->u.id.data, r->u.id.length);
++		break;
++	case ISAKMP_PAYLOAD_CERT:
++	case ISAKMP_PAYLOAD_CR:
++		r->u.cert.encoding = fetch1();
++		hex_dump("cert.encoding", &r->u.cert.encoding, UINT8);
++		r->u.cert.length = length - 5;
++		fetchn(r->u.cert.data, r->u.cert.length);
++		hex_dump("cert.data", r->u.cert.data, r->u.cert.length);
++		break;
++	case ISAKMP_PAYLOAD_N:
++		r->u.n.doi = fetch4();
++		hex_dump("n.doi", &r->u.n.doi, UINT32);
++		r->u.n.protocol = fetch1();
++		hex_dump("n.protocol", &r->u.n.protocol, UINT8);
++		r->u.n.spi_length = fetch1();
++		hex_dump("n.spi_length", &r->u.n.spi_length, UINT8);
++		r->u.n.type = fetch2();
++		hex_dump("n.type", &r->u.n.type, UINT16);
++		if (r->u.n.spi_length + 12u > length) {
++			*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++			return r;
++		}
++		r->u.n.spi = xallocc(r->u.n.spi_length);
++		fetchn(r->u.n.spi, r->u.n.spi_length);
++		hex_dump("n.spi", r->u.n.spi, r->u.n.spi_length);
++		r->u.n.data_length = length - 12 - r->u.n.spi_length;
++		r->u.n.data = xallocc(r->u.n.data_length);
++		fetchn(r->u.n.data, r->u.n.data_length);
++		hex_dump("n.data", r->u.n.data, r->u.n.data_length);
++		break;
++	case ISAKMP_PAYLOAD_D:
++		r->u.n.doi = fetch4(); /*FIXME: huuuh? */
++		hex_dump("n.doi", &r->u.n.doi, UINT32);
++		r->u.n.protocol = fetch1();
++		hex_dump("n.protocol", &r->u.n.protocol, UINT8);
++		r->u.n.spi_length = fetch1();
++		hex_dump("n.spi_length", &r->u.n.spi_length, UINT8);
++		r->u.d.num_spi = fetch2();
++		hex_dump("d.num_spi", &r->u.d.num_spi, UINT16);
++		if (r->u.d.num_spi * r->u.n.spi_length + 12u != length) {
++			*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++			return r;
++		}
++		r->u.d.spi = xallocc(sizeof(uint8_t *) * r->u.d.num_spi);
++		{
++			int i;
++			for (i = 0; i < r->u.d.num_spi; i++) {
++				r->u.d.spi[i] = xallocc(r->u.d.spi_length);
++				fetchn(r->u.d.spi[i], r->u.d.spi_length);
++				hex_dump("d.spi", r->u.d.spi[i], r->u.d.spi_length);
++			}
++		}
++		break;
++	case ISAKMP_PAYLOAD_MODECFG_ATTR:
++		r->u.modecfg.type = fetch1();
++		hex_dump("modecfg.type", &r->u.modecfg.type, UINT8);
++		if (fetch1() != 0) {
++			*reject = ISAKMP_N_PAYLOAD_MALFORMED;
++			return r;
++		}
++		r->u.t.id = fetch2();
++		hex_dump("t.id", &r->u.t.id, UINT16);
++		length -= 8;
++		r->u.t.attributes = parse_isakmp_attributes(&data, length, reject);
++		data_len -= olength - 8;
++		break;
++
++	default:
++		abort();
++	}
++	*data_p = data;
++	*data_len_p = data_len;
++	hex_dump("DONE PARSING PAYLOAD type", &type, UINT8);
++	r->next = parse_isakmp_payload(next_type, data_p, data_len_p, reject);
++	return r;
+ }
+ 
+-struct isakmp_packet *
+-parse_isakmp_packet (const uint8_t *data, size_t data_len, uint16_t *reject)
++struct isakmp_packet *parse_isakmp_packet(const uint8_t * data, size_t data_len, uint16_t * reject)
+ {
+-  uint16_t reason = 0;
+-  uint8_t payload;
+-  struct isakmp_packet *r = new_isakmp_packet();
+-  size_t o_data_len = data_len;
+-  
+-  if (data_len < ISAKMP_PAYLOAD_O)
+-    {
+-      reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
+-      goto error;
+-    }
+-  
+-DEBUG(3, printf("\nBEGIN_PARSE\n"));
+-  fetchn (r->i_cookie, ISAKMP_COOKIE_LENGTH);
+-hex_dump("i_cookie", r->i_cookie, ISAKMP_COOKIE_LENGTH);
+-  fetchn (r->r_cookie, ISAKMP_COOKIE_LENGTH);
+-hex_dump("r_cookie", r->r_cookie, ISAKMP_COOKIE_LENGTH);
+-  payload = fetch1 ();
+-hex_dump("payload", &payload, sizeof(payload));
++	uint16_t reason = 0;
++	uint8_t payload;
++	struct isakmp_packet *r = new_isakmp_packet();
++	size_t o_data_len = data_len;
+ 
+-  r->isakmp_version = fetch1 ();
+-hex_dump("isakmp_version", &r->isakmp_version, sizeof(r->isakmp_version));
+-  if (r->isakmp_version > ISAKMP_VERSION)
+-    {
+-      if ((r->isakmp_version & 0xF0) >= (ISAKMP_VERSION & 0xF0))
+-	reason = ISAKMP_N_INVALID_MAJOR_VERSION;
+-      else
+-	reason = ISAKMP_N_INVALID_MINOR_VERSION;
+-      goto error;
+-    }
++	if (data_len < ISAKMP_PAYLOAD_O) {
++		reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
++		goto error;
++	}
+ 
+-  r->exchange_type = fetch1 ();
+-hex_dump("exchange_type", &r->exchange_type, sizeof(r->exchange_type));
+-  r->flags = fetch1 ();
+-hex_dump("flags", &r->flags, sizeof(r->flags));
+-  r->message_id = fetch4 ();
+-hex_dump("message_id", &r->message_id, sizeof(r->message_id));
++	DEBUG(3, printf("\nBEGIN_PARSE\n"));
++	fetchn(r->i_cookie, ISAKMP_COOKIE_LENGTH);
++	hex_dump("i_cookie", r->i_cookie, ISAKMP_COOKIE_LENGTH);
++	fetchn(r->r_cookie, ISAKMP_COOKIE_LENGTH);
++	hex_dump("r_cookie", r->r_cookie, ISAKMP_COOKIE_LENGTH);
++	payload = fetch1();
++	hex_dump("payload", &payload, UINT8);
+ 
+-  if (fetch4() != o_data_len)
+-    {
+-      reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
+-      goto error;
+-    }
+-hex_dump("len", &o_data_len, sizeof(o_data_len));
+-  
+-  r->payload = parse_isakmp_payload (payload, &data, &data_len, &reason);
+-  if (reason != 0)
+-    goto error;
+-  
+-DEBUG(3, printf("PARSE_OK\n\n"));
+-  return r;
++	r->isakmp_version = fetch1();
++	hex_dump("isakmp_version", &r->isakmp_version, UINT8);
++	if (r->isakmp_version > ISAKMP_VERSION) {
++		if ((r->isakmp_version & 0xF0) >= (ISAKMP_VERSION & 0xF0))
++			reason = ISAKMP_N_INVALID_MAJOR_VERSION;
++		else
++			reason = ISAKMP_N_INVALID_MINOR_VERSION;
++		goto error;
++	}
+ 
+- error:
+-  free_isakmp_packet(r);
+-  if (reject)
+-    *reject = reason;
+-  return NULL;
++	r->exchange_type = fetch1();
++	hex_dump("exchange_type", &r->exchange_type, UINT8);
++	r->flags = fetch1();
++	hex_dump("flags", &r->flags, UINT8);
++	r->message_id = fetch4();
++	hex_dump("message_id", &r->message_id, sizeof(r->message_id));
++
++	if (fetch4() != o_data_len) {
++		reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
++		goto error;
++	}
++	hex_dump("len", &o_data_len, UINT32);
++
++	r->payload = parse_isakmp_payload(payload, &data, &data_len, &reason);
++	if (reason != 0)
++		goto error;
++
++	DEBUG(3, printf("PARSE_OK\n\n"));
++	return r;
++
++      error:
++	free_isakmp_packet(r);
++	if (reject)
++		*reject = reason;
++	return NULL;
+ }
+ 
+-const char *
+-isakmp_notify_to_error (uint16_t notify)
++const char *isakmp_notify_to_error(uint16_t notify)
+ {
+-  static const struct {
+-    uint16_t id;
+-    const char *name;
+-  } data[] = {
+-    { ISAKMP_N_INVALID_PAYLOAD_TYPE, "INVALID_PAYLOAD_TYPE" },
+-    { ISAKMP_N_DOI_NOT_SUPPORTED, "DOI_NOT_SUPPORTED" },
+-    { ISAKMP_N_SITUATION_NOT_SUPPORTED, "SITUATION_NOT_SUPPORTED" },
+-    { ISAKMP_N_INVALID_COOKIE, "INVALID_COOKIE" },
+-    { ISAKMP_N_INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION" },
+-    { ISAKMP_N_INVALID_MINOR_VERSION, "INVALID_MINOR_VERSION" },
+-    { ISAKMP_N_INVALID_EXCHANGE_TYPE, "INVALID_EXCHANGE_TYPE" },
+-    { ISAKMP_N_INVALID_FLAGS, "INVALID_FLAGS" },
+-    { ISAKMP_N_INVALID_MESSAGE_ID, "INVALID_MESSAGE_ID" },
+-    { ISAKMP_N_INVALID_PROTOCOL_ID, "INVALID_PROTOCOL_ID" },
+-    { ISAKMP_N_INVALID_SPI, "INVALID_SPI" },
+-    { ISAKMP_N_INVALID_TRANSFORM_ID, "INVALID_TRANSFORM_ID" },
+-    { ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES_NOT_SUPPORTED" },
+-    { ISAKMP_N_NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN" },
+-    { ISAKMP_N_BAD_PROPOSAL_SYNTAX, "BAD_PROPOSAL_SYNTAX" },
+-    { ISAKMP_N_PAYLOAD_MALFORMED, "PAYLOAD_MALFORMED" },
+-    { ISAKMP_N_INVALID_KEY_INFORMATION, "INVALID_KEY_INFORMATION" },
+-    { ISAKMP_N_INVALID_ID_INFORMATION, "INVALID_ID_INFORMATION" },
+-    { ISAKMP_N_INVALID_CERT_ENCODING, "INVALID_CERT_ENCODING" },
+-    { ISAKMP_N_INVALID_CERTIFICATE, "INVALID_CERTIFICATE" },
+-    { ISAKMP_N_CERT_TYPE_UNSUPPORTED, "CERT_TYPE_UNSUPPORTED" },
+-    { ISAKMP_N_INVALID_CERT_AUTHORITY, "INVALID_CERT_AUTHORITY" },
+-    { ISAKMP_N_INVALID_HASH_INFORMATION, "INVALID_HASH_INFORMATION" },
+-    { ISAKMP_N_AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED" },
+-    { ISAKMP_N_INVALID_SIGNATURE, "INVALID_SIGNATURE" },
+-    { ISAKMP_N_ADDRESS_NOTIFICATION, "ADDRESS_NOTIFICATION" },
+-    { ISAKMP_N_NOTIFY_SA_LIFETIME, "NOTIFY_SA_LIFETIME" },
+-    { ISAKMP_N_CERTIFICATE_UNAVAILABLE, "CERTIFICATE_UNAVAILABLE" },
+-    { ISAKMP_N_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED_EXCHANGE_TYPE" },
+-    { ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS, "UNEQUAL_PAYLOAD_LENGTHS" }
+-  };
+-  size_t i;
+-  static char number[10];
+-  
+-  for (i = 0; i < sizeof (data) / sizeof (data[0]); i++)
+-    if (data[i].id == notify)
+-      return data[i].name;
+-  sprintf (number, "%d", notify);
+-  return number;
++	static const struct {
++		uint16_t id;
++		const char *name;
++	} data[] = {
++		{ ISAKMP_N_INVALID_PAYLOAD_TYPE, "INVALID_PAYLOAD_TYPE"},
++		{ ISAKMP_N_DOI_NOT_SUPPORTED, "DOI_NOT_SUPPORTED"},
++		{ ISAKMP_N_SITUATION_NOT_SUPPORTED, "SITUATION_NOT_SUPPORTED"},
++		{ ISAKMP_N_INVALID_COOKIE, "INVALID_COOKIE"},
++		{ ISAKMP_N_INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
++		{ ISAKMP_N_INVALID_MINOR_VERSION, "INVALID_MINOR_VERSION"},
++		{ ISAKMP_N_INVALID_EXCHANGE_TYPE, "INVALID_EXCHANGE_TYPE"},
++		{ ISAKMP_N_INVALID_FLAGS, "INVALID_FLAGS"},
++		{ ISAKMP_N_INVALID_MESSAGE_ID, "INVALID_MESSAGE_ID"},
++		{ ISAKMP_N_INVALID_PROTOCOL_ID, "INVALID_PROTOCOL_ID"},
++		{ ISAKMP_N_INVALID_SPI, "INVALID_SPI"},
++		{ ISAKMP_N_INVALID_TRANSFORM_ID, "INVALID_TRANSFORM_ID"},
++		{ ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES_NOT_SUPPORTED"},
++		{ ISAKMP_N_NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN"},
++		{ ISAKMP_N_BAD_PROPOSAL_SYNTAX, "BAD_PROPOSAL_SYNTAX"},
++		{ ISAKMP_N_PAYLOAD_MALFORMED, "PAYLOAD_MALFORMED"},
++		{ ISAKMP_N_INVALID_KEY_INFORMATION, "INVALID_KEY_INFORMATION"},
++		{ ISAKMP_N_INVALID_ID_INFORMATION, "INVALID_ID_INFORMATION"},
++		{ ISAKMP_N_INVALID_CERT_ENCODING, "INVALID_CERT_ENCODING"},
++		{ ISAKMP_N_INVALID_CERTIFICATE, "INVALID_CERTIFICATE"},
++		{ ISAKMP_N_CERT_TYPE_UNSUPPORTED, "CERT_TYPE_UNSUPPORTED"},
++		{ ISAKMP_N_INVALID_CERT_AUTHORITY, "INVALID_CERT_AUTHORITY"},
++		{ ISAKMP_N_INVALID_HASH_INFORMATION, "INVALID_HASH_INFORMATION"},
++		{ ISAKMP_N_AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED"},
++		{ ISAKMP_N_INVALID_SIGNATURE, "INVALID_SIGNATURE"},
++		{ ISAKMP_N_ADDRESS_NOTIFICATION, "ADDRESS_NOTIFICATION"},
++		{ ISAKMP_N_NOTIFY_SA_LIFETIME, "NOTIFY_SA_LIFETIME"},
++		{ ISAKMP_N_CERTIFICATE_UNAVAILABLE, "CERTIFICATE_UNAVAILABLE"},
++		{ ISAKMP_N_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED_EXCHANGE_TYPE"},
++		{ ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS, "UNEQUAL_PAYLOAD_LENGTHS"}
++	};
++	size_t i;
++	static char number[10];
++
++	for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
++		if (data[i].id == notify)
++			return data[i].name;
++	sprintf(number, "%d", notify);
++	return number;
+ }
+ 
+ void test_pack_unpack(void)
+ {
+-  static const uint8_t pack[] = {
+-    0x7f, 0xba, 0x51, 0x29, 0x11, 0x9e, 0x76, 0xf7, 0x9a, 0x71, 0xee, 0x70,
+-    0xaa, 0x82, 0xb9, 0x7f, 0x01, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+-    0x00, 0x00, 0x01, 0x4c, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
+-    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01,
+-    0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x05,
+-    0x80, 0x02, 0x00, 0x01, 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01,
+-    0x0a, 0x00, 0x00, 0x84, 0x1b, 0x1d, 0x4b, 0x29, 0x0e, 0x29, 0xb9, 0x6f,
+-    0x18, 0x34, 0xd1, 0x2d, 0xba, 0x92, 0x7c, 0x53, 0x35, 0x76, 0x0e, 0x3b,
+-    0x25, 0x92, 0x4f, 0x7c, 0x1e, 0x31, 0x41, 0x8c, 0xb9, 0xe3, 0xda, 0xf7,
+-    0x53, 0xd3, 0x22, 0x8e, 0xff, 0xeb, 0xed, 0x5b, 0x95, 0x56, 0x8d, 0xba,
+-    0xa8, 0xe3, 0x2a, 0x9b, 0xb4, 0x04, 0x5c, 0x90, 0xf0, 0xfe, 0x92, 0xc8,
+-    0x57, 0xa2, 0xc6, 0x0c, 0x85, 0xbb, 0x56, 0xe8, 0x1c, 0xa7, 0x2c, 0x57,
+-    0x04, 0xb6, 0xe0, 0x43, 0x82, 0xe1, 0x9f, 0x0b, 0xa6, 0x8b, 0xce, 0x7f,
+-    0x9b, 0x75, 0xbb, 0xd3, 0xff, 0x0e, 0x89, 0x19, 0xaf, 0xc6, 0x2e, 0xf6,
+-    0x92, 0x06, 0x46, 0x4f, 0xc7, 0x97, 0x22, 0xf4, 0xa6, 0xf9, 0x26, 0x34,
+-    0x04, 0x33, 0x89, 0x34, 0xa9, 0x2f, 0x81, 0x92, 0xd3, 0x21, 0x4f, 0x45,
+-    0xbe, 0x38, 0x12, 0x26, 0xec, 0x87, 0x45, 0xdd, 0x10, 0x1c, 0xd6, 0x16,
+-    0x05, 0x00, 0x00, 0x18, 0x77, 0xdf, 0x37, 0x3c, 0x03, 0x02, 0xe2, 0xc8,
+-    0xe1, 0x2f, 0x92, 0xf0, 0x2e, 0xa2, 0xa6, 0x00, 0x17, 0x8f, 0xdf, 0xb4,
+-    0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x01, 0xf4, 0xcd, 0xb4, 0x53, 0x6d,
+-    0x0d, 0x00, 0x00, 0x14, 0x07, 0x47, 0x8d, 0xa7, 0x0b, 0xd6, 0xd1, 0x66,
+-    0x7a, 0xaf, 0x2e, 0x61, 0x2a, 0x91, 0x80, 0x94, 0x0d, 0x00, 0x00, 0x14,
+-    0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2,
+-    0x74, 0xcc, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89,
+-    0xdf, 0xd6, 0xb7, 0x12, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13,
+-    0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00,
+-    0x00, 0x00, 0x00, 0x14, 0x1f, 0x07, 0xf7, 0x0e, 0xaa, 0x65, 0x14, 0xd3,
+-    0xb0, 0xfa, 0x96, 0x54, 0x2a, 0x50, 0x03, 0x05 };
+-  uint8_t *unpack;
+-  size_t unpack_len;
+-  struct isakmp_packet * p;
+-  uint16_t reject;
+-  
+-  p = parse_isakmp_packet (pack, sizeof (pack), &reject);
+-  flatten_isakmp_packet (p, &unpack, &unpack_len, 8);
+-  if (unpack_len != sizeof (pack)
+-      || memcmp (unpack, pack, sizeof (pack)) != 0)
+-    abort ();
+-  free (unpack);
+-  free_isakmp_packet (p);
++	static const uint8_t pack[] = {
++		0x7f, 0xba, 0x51, 0x29, 0x11, 0x9e, 0x76, 0xf7, 0x9a, 0x71, 0xee, 0x70,
++		0xaa, 0x82, 0xb9, 0x7f, 0x01, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
++		0x00, 0x00, 0x01, 0x4c, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
++		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01,
++		0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x05,
++		0x80, 0x02, 0x00, 0x01, 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01,
++		0x0a, 0x00, 0x00, 0x84, 0x1b, 0x1d, 0x4b, 0x29, 0x0e, 0x29, 0xb9, 0x6f,
++		0x18, 0x34, 0xd1, 0x2d, 0xba, 0x92, 0x7c, 0x53, 0x35, 0x76, 0x0e, 0x3b,
++		0x25, 0x92, 0x4f, 0x7c, 0x1e, 0x31, 0x41, 0x8c, 0xb9, 0xe3, 0xda, 0xf7,
++		0x53, 0xd3, 0x22, 0x8e, 0xff, 0xeb, 0xed, 0x5b, 0x95, 0x56, 0x8d, 0xba,
++		0xa8, 0xe3, 0x2a, 0x9b, 0xb4, 0x04, 0x5c, 0x90, 0xf0, 0xfe, 0x92, 0xc8,
++		0x57, 0xa2, 0xc6, 0x0c, 0x85, 0xbb, 0x56, 0xe8, 0x1c, 0xa7, 0x2c, 0x57,
++		0x04, 0xb6, 0xe0, 0x43, 0x82, 0xe1, 0x9f, 0x0b, 0xa6, 0x8b, 0xce, 0x7f,
++		0x9b, 0x75, 0xbb, 0xd3, 0xff, 0x0e, 0x89, 0x19, 0xaf, 0xc6, 0x2e, 0xf6,
++		0x92, 0x06, 0x46, 0x4f, 0xc7, 0x97, 0x22, 0xf4, 0xa6, 0xf9, 0x26, 0x34,
++		0x04, 0x33, 0x89, 0x34, 0xa9, 0x2f, 0x81, 0x92, 0xd3, 0x21, 0x4f, 0x45,
++		0xbe, 0x38, 0x12, 0x26, 0xec, 0x87, 0x45, 0xdd, 0x10, 0x1c, 0xd6, 0x16,
++		0x05, 0x00, 0x00, 0x18, 0x77, 0xdf, 0x37, 0x3c, 0x03, 0x02, 0xe2, 0xc8,
++		0xe1, 0x2f, 0x92, 0xf0, 0x2e, 0xa2, 0xa6, 0x00, 0x17, 0x8f, 0xdf, 0xb4,
++		0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x01, 0xf4, 0xcd, 0xb4, 0x53, 0x6d,
++		0x0d, 0x00, 0x00, 0x14, 0x07, 0x47, 0x8d, 0xa7, 0x0b, 0xd6, 0xd1, 0x66,
++		0x7a, 0xaf, 0x2e, 0x61, 0x2a, 0x91, 0x80, 0x94, 0x0d, 0x00, 0x00, 0x14,
++		0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2,
++		0x74, 0xcc, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89,
++		0xdf, 0xd6, 0xb7, 0x12, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13,
++		0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00,
++		0x00, 0x00, 0x00, 0x14, 0x1f, 0x07, 0xf7, 0x0e, 0xaa, 0x65, 0x14, 0xd3,
++		0xb0, 0xfa, 0x96, 0x54, 0x2a, 0x50, 0x03, 0x05
++	};
++	uint8_t *unpack;
++	size_t unpack_len;
++	struct isakmp_packet *p;
++	uint16_t reject;
++
++	p = parse_isakmp_packet(pack, sizeof(pack), &reject);
++	flatten_isakmp_packet(p, &unpack, &unpack_len, 8);
++	if (unpack_len != sizeof(pack)
++		|| memcmp(unpack, pack, sizeof(pack)) != 0)
++		abort();
++	free(unpack);
++	free_isakmp_packet(p);
+ }
+diff -Nurd vpnc-0.2-rm+zomb.1/isakmp-pkt.h new/isakmp-pkt.h
+--- vpnc-0.2-rm+zomb.1/isakmp-pkt.h	2003-10-31 14:16:39.000000000 +0100
++++ new/isakmp-pkt.h	2004-06-10 11:19:53.000000000 +0200
+@@ -16,6 +16,8 @@
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+ 
++#ifndef __ISAKMP_PKT_H__
++#define __ISAKMP_PKT_H__
+ #if defined(__linux__)
+ #include <stdint.h>
+ #endif
+@@ -24,113 +26,109 @@
+ #include "isakmp.h"
+ 
+ struct isakmp_attribute {
+-  struct isakmp_attribute *next;
+-  uint16_t type;
+-  enum {
+-    isakmp_attr_lots,
+-    isakmp_attr_16,
+-    isakmp_attr_2x8
+-  } af;
+-  union {
+-    uint16_t attr_16;
+-    uint8_t attr_2x8[2];
+-    struct {
+-      uint16_t length;
+-      uint8_t *data;
+-    } lots;
+-  } u;
++	struct isakmp_attribute *next;
++	uint16_t type;
++	enum {
++		isakmp_attr_lots,
++		isakmp_attr_16,
++		isakmp_attr_2x8
++	} af;
++	union {
++		uint16_t attr_16;
++		uint8_t attr_2x8[2];
++		struct {
++			uint16_t length;
++			uint8_t *data;
++		} lots;
++	} u;
+ };
+ 
+-struct isakmp_payload 
+-{
+-  struct isakmp_payload *next;
+-  enum isakmp_payload_enum type;
+-  union {
+-    struct {
+-      uint32_t doi;
+-      uint32_t situation;
+-      struct isakmp_payload *proposals;
+-    } sa;
+-    struct {
+-      uint8_t number;
+-      uint8_t prot_id;
+-      uint8_t spi_size;
+-      uint8_t *spi;
+-      struct isakmp_payload *transforms;
+-    } p;
+-    struct {
+-      uint8_t number;
+-      uint8_t id;
+-      struct isakmp_attribute *attributes;
+-    } t;
+-    struct {
+-      uint16_t length;
+-      uint8_t *data;
+-    } ke, hash, sig, nonce, vid;
+-    struct {
+-      uint8_t type;
+-      uint8_t protocol;
+-      uint16_t port;
+-      uint16_t length;
+-      uint8_t *data;
+-    } id;
+-    struct {
+-      uint8_t encoding;
+-      uint16_t length;
+-      uint8_t *data;
+-    } cert, cr;
+-    struct {
+-      uint32_t doi;
+-      uint8_t protocol;
+-      uint8_t spi_length;
+-      uint8_t *spi;
+-      uint16_t type;
+-      uint16_t data_length;
+-      uint8_t *data;
+-    } n;
+-    struct {
+-      uint32_t doi;
+-      uint8_t protocol;
+-      uint8_t spi_length;
+-      uint16_t num_spi;
+-      uint8_t **spi;
+-    } d;
+-    struct {
+-      uint8_t type;
+-      uint16_t id;
+-      struct isakmp_attribute *attributes;
+-    } modecfg;
+-  } u;
++struct isakmp_payload {
++	struct isakmp_payload *next;
++	enum isakmp_payload_enum type;
++	union {
++		struct {
++			uint32_t doi;
++			uint32_t situation;
++			struct isakmp_payload *proposals;
++		} sa;
++		struct {
++			uint8_t number;
++			uint8_t prot_id;
++			uint8_t spi_size;
++			uint8_t *spi;
++			struct isakmp_payload *transforms;
++		} p;
++		struct {
++			uint8_t number;
++			uint8_t id;
++			struct isakmp_attribute *attributes;
++		} t;
++		struct {
++			uint16_t length;
++			uint8_t *data;
++		} ke, hash, sig, nonce, vid;
++		struct {
++			uint8_t type;
++			uint8_t protocol;
++			uint16_t port;
++			uint16_t length;
++			uint8_t *data;
++		} id;
++		struct {
++			uint8_t encoding;
++			uint16_t length;
++			uint8_t *data;
++		} cert, cr;
++		struct {
++			uint32_t doi;
++			uint8_t protocol;
++			uint8_t spi_length;
++			uint8_t *spi;
++			uint16_t type;
++			uint16_t data_length;
++			uint8_t *data;
++		} n;
++		struct {
++			uint32_t doi;
++			uint8_t protocol;
++			uint8_t spi_length;
++			uint16_t num_spi;
++			uint8_t **spi;
++		} d;
++		struct {
++			uint8_t type;
++			uint16_t id;
++			struct isakmp_attribute *attributes;
++		} modecfg;
++	} u;
+ };
+ 
+-struct isakmp_packet 
+-{
+-  uint8_t i_cookie[ISAKMP_COOKIE_LENGTH];
+-  uint8_t r_cookie[ISAKMP_COOKIE_LENGTH];
+-  uint8_t isakmp_version;
+-  uint8_t exchange_type;
+-  uint8_t flags;
+-  uint32_t message_id;
+-  struct isakmp_payload *payload;
++struct isakmp_packet {
++	uint8_t i_cookie[ISAKMP_COOKIE_LENGTH];
++	uint8_t r_cookie[ISAKMP_COOKIE_LENGTH];
++	uint8_t isakmp_version;
++	uint8_t exchange_type;
++	uint8_t flags;
++	uint32_t message_id;
++	struct isakmp_payload *payload;
+ };
+ 
+-extern void * xallocc (size_t x);
+-extern struct isakmp_packet * new_isakmp_packet(void);
+-extern struct isakmp_payload * new_isakmp_payload(uint8_t);
+-extern struct isakmp_payload * 
+-  new_isakmp_data_payload(uint8_t type, const void *data, size_t data_length);
+-extern struct isakmp_attribute * 
+-  new_isakmp_attribute(uint16_t, struct isakmp_attribute *);
+-extern struct isakmp_attribute * 
+-  new_isakmp_attribute_16 (uint16_t type, uint16_t data, 
+-			   struct isakmp_attribute *next);
++extern void *xallocc(size_t x);
++extern struct isakmp_packet *new_isakmp_packet(void);
++extern struct isakmp_payload *new_isakmp_payload(uint8_t);
++extern struct isakmp_payload *new_isakmp_data_payload(uint8_t type, const void *data,
++	size_t data_length);
++extern struct isakmp_attribute *new_isakmp_attribute(uint16_t, struct isakmp_attribute *);
++extern struct isakmp_attribute *new_isakmp_attribute_16(uint16_t type, uint16_t data,
++	struct isakmp_attribute *next);
+ extern void free_isakmp_packet(struct isakmp_packet *p);
+-extern void flatten_isakmp_payload (struct isakmp_payload *p, 
+-				    uint8_t **result, size_t *size);
+-extern void flatten_isakmp_packet (struct isakmp_packet *p, 
+-				   uint8_t **result, size_t *size, size_t blksz);
+-extern struct isakmp_packet * parse_isakmp_packet (const uint8_t *data, 
+-						   size_t data_len, 
+-						   uint16_t *reject);
+-extern const char * isakmp_notify_to_error (uint16_t notify);
++extern void flatten_isakmp_payload(struct isakmp_payload *p, uint8_t ** result, size_t * size);
++extern void flatten_isakmp_packet(struct isakmp_packet *p,
++	uint8_t ** result, size_t * size, size_t blksz);
++extern struct isakmp_packet *parse_isakmp_packet(const uint8_t * data,
++	size_t data_len, uint16_t * reject);
++extern const char *isakmp_notify_to_error(uint16_t notify);
+ extern void test_pack_unpack(void);
++
++#endif
+diff -Nurd vpnc-0.2-rm+zomb.1/Makefile new/Makefile
+--- vpnc-0.2-rm+zomb.1/Makefile	2004-05-03 00:10:09.000000000 +0200
++++ new/Makefile	2004-06-03 16:48:02.000000000 +0200
+@@ -40,12 +40,16 @@
+ SYSDEP=sysdep-svr4.o
+ endif
+ 
+-vpnc : vpnc.o isakmp-pkt.o tunip.o $(SYSDEP) dh.o math_group.o
++vpnc : vpnc.o isakmp-pkt.o tunip.o config.o $(SYSDEP) dh.o math_group.o
+ 	$(CC) -o $@ $^ $(LDFLAGS)
+ 
+-vpnc.o : isakmp.h isakmp-pkt.h dh.h sysdep.h math_group.h vpnc.h VERSION
+-isakmp-pkt.o : isakmp.h isakmp-pkt.h vpnc.h
+-tunip.o : sysdep.h vpnc.h
++vpnc.ps : vpnc.c
++	enscript -E -G -T 4 --word-wrap -o- $^ | psnup -2 /dev/stdin $@
++
++vpnc.o : isakmp.h isakmp-pkt.h dh.h sysdep.h math_group.h config.h VERSION
++isakmp-pkt.o : isakmp.h isakmp-pkt.h config.h
++tunip.o : sysdep.h vpnc.h config.h
++config.o : vpnc.h config.h VERSION
+ dh.o : dh.h math_group.h
+ math_group.o : math_group.h
+ 
+diff -Nurd vpnc-0.2-rm+zomb.1/math_group.c new/math_group.c
+--- vpnc-0.2-rm+zomb.1/math_group.c	2004-05-13 22:35:28.000000000 +0200
++++ new/math_group.c	2004-05-30 14:32:32.000000000 +0200
+@@ -43,16 +43,16 @@
+ #include "math_group.h"
+ 
+ /* We do not want to export these definitions.  */
+-int modp_getlen (struct group *);
+-void modp_getraw (struct group *, gcry_mpi_t, unsigned char *);
+-int modp_setraw (struct group *, gcry_mpi_t, unsigned char *, int);
+-int modp_setrandom (struct group *, gcry_mpi_t);
+-int modp_operation (struct group *, gcry_mpi_t, gcry_mpi_t, gcry_mpi_t);
++int modp_getlen(struct group *);
++void modp_getraw(struct group *, gcry_mpi_t, unsigned char *);
++int modp_setraw(struct group *, gcry_mpi_t, unsigned char *, int);
++int modp_setrandom(struct group *, gcry_mpi_t);
++int modp_operation(struct group *, gcry_mpi_t, gcry_mpi_t, gcry_mpi_t);
+ 
+ struct modp_group {
+-  gcry_mpi_t gen;			/* Generator */
+-  gcry_mpi_t p;				/* Prime */
+-  gcry_mpi_t a, b, c, d;
++	gcry_mpi_t gen; /* Generator */
++	gcry_mpi_t p; /* Prime */
++	gcry_mpi_t a, b, c, d;
+ };
+ 
+ /*
+@@ -68,64 +68,65 @@
+  * group order, e.g. q = 2**768.
+  */
+ 
+-struct modp_dscr oakley_modp[] =
+-{
+-  { OAKLEY_GRP_1, 72,	/* This group is insecure, only sufficient for DES */
+-    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+-    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+-    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+-    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
+-    "2"
+-  },
+-  { OAKLEY_GRP_2, 82,	/* This group is a bit better */
+-    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+-    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+-    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+-    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+-    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+-    "FFFFFFFFFFFFFFFF",
+-    "2"
+-  },
+-  { OAKLEY_GRP_5, 102,	/* This group is yet a bit better, but non-standard */
+-    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+-    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+-    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+-    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+-    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+-    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+-    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+-    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
+-    "2"
+-  },
++struct modp_dscr oakley_modp[] = {
++	{
++		OAKLEY_GRP_1, 72, /* This group is insecure, only sufficient for DES */
++		"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
++		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
++		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
++		"E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
++		"2"
++	},
++	{
++		OAKLEY_GRP_2, 82, /* This group is a bit better */
++		"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
++		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
++		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
++		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
++		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
++		"FFFFFFFFFFFFFFFF",
++		"2"
++	},
++	{
++		OAKLEY_GRP_5, 102, /* This group is yet a bit better, but non-standard */
++		"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
++		"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
++		"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
++		"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
++		"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
++		"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
++		"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
++		"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
++		"2"
++	},
+ };
+ 
+-
+ /* XXX I want to get rid of the casting here.  */
+ struct group groups[] = {
+-  {
+-    MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], 0, 0, 0, 0, 0,
+-    (int (*) (struct group *))modp_getlen,
+-    (void (*) (struct group *, void *, unsigned char *))modp_getraw,
+-    (int (*) (struct group *, void *, unsigned char *, int))modp_setraw,
+-    (int (*) (struct group *, void *))modp_setrandom,
+-    (int (*) (struct group *, void *, void *, void *))modp_operation
+-  },
+-  {
+-    MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], 0, 0, 0, 0, 0,
+-    (int (*) (struct group *))modp_getlen,
+-    (void (*) (struct group *, void *, unsigned char *))modp_getraw,
+-    (int (*) (struct group *, void *, unsigned char *, int))modp_setraw,
+-    (int (*) (struct group *, void *))modp_setrandom,
+-    (int (*) (struct group *, void *, void *, void *))modp_operation
+-  },
+-  {
+-    MODP, OAKLEY_GRP_5, 0, &oakley_modp[2], 0, 0, 0, 0, 0,
+-    (int (*) (struct group *))modp_getlen,
+-    (void (*) (struct group *, void *, unsigned char *))modp_getraw,
+-    (int (*) (struct group *, void *, unsigned char *, int))modp_setraw,
+-    (int (*) (struct group *, void *))modp_setrandom,
+-    (int (*) (struct group *, void *, void *, void *))modp_operation
+-  },
++	{
++		MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], 0, 0, 0, 0, 0,
++		(int (*)(struct group *))modp_getlen,
++		(void (*)(struct group *, void *, unsigned char *))modp_getraw,
++		(int (*)(struct group *, void *, unsigned char *, int))modp_setraw,
++		(int (*)(struct group *, void *))modp_setrandom,
++		(int (*)(struct group *, void *, void *, void *))modp_operation
++	},
++	{
++		MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], 0, 0, 0, 0, 0,
++		(int (*)(struct group *))modp_getlen,
++		(void (*)(struct group *, void *, unsigned char *))modp_getraw,
++		(int (*)(struct group *, void *, unsigned char *, int))modp_setraw,
++		(int (*)(struct group *, void *))modp_setrandom,
++		(int (*)(struct group *, void *, void *, void *))modp_operation
++	},
++	{
++		MODP, OAKLEY_GRP_5, 0, &oakley_modp[2], 0, 0, 0, 0, 0,
++		(int (*)(struct group *))modp_getlen,
++		(void (*)(struct group *, void *, unsigned char *))modp_getraw,
++		(int (*)(struct group *, void *, unsigned char *, int))modp_setraw,
++		(int (*)(struct group *, void *))modp_setrandom,
++		(int (*)(struct group *, void *, void *, void *))modp_operation
++	},
+ };
+ 
+ /*
+@@ -133,188 +134,174 @@
+  * this is done by converting the values given in the describtion
+  * and converting them to their native representation.
+  */
+-void
+-group_init (void)
++void group_init(void)
+ {
+-  int i;
++	int i;
+ 
+-  for (i = sizeof (groups) / sizeof (groups[0]) - 1; i >= 0; i--) {
+-    assert(groups[i].type == MODP);
+-    modp_init (&groups[i]); /* Initialize an over GF(p) */
+-  }
++	for (i = sizeof(groups) / sizeof(groups[0]) - 1; i >= 0; i--) {
++		assert(groups[i].type == MODP);
++		modp_init(&groups[i]); /* Initialize an over GF(p) */
++	}
+ }
+ 
+-struct group *
+-group_get (int id)
++struct group *group_get(int id)
+ {
+-  struct group *new, *clone;
++	struct group *new, *clone;
+ 
+-  assert(id >= 1);
+-  assert(id <= (int)(sizeof (groups) / sizeof (groups[0])));
++	assert(id >= 1);
++	assert(id <= (int)(sizeof(groups) / sizeof(groups[0])));
+ 
+-  clone = &groups[id - 1];
++	clone = &groups[id - 1];
+ 
+-  new = malloc (sizeof *new);
+-  assert(new);
++	new = malloc(sizeof *new);
++	assert(new);
+ 
+-  assert(clone->type == MODP);
+-  new = modp_clone (new, clone);
+-  return new;
++	assert(clone->type == MODP);
++	new = modp_clone(new, clone);
++	return new;
+ }
+ 
+-void
+-group_free (struct group *grp)
++void group_free(struct group *grp)
+ {
+-  assert (grp->type == MODP);
+-  modp_free (grp);
+-  free (grp);
++	assert(grp->type == MODP);
++	modp_free(grp);
++	free(grp);
+ }
+ 
+-struct group *
+-modp_clone (struct group *new, struct group *clone)
++struct group *modp_clone(struct group *new, struct group *clone)
+ {
+-  struct modp_group *new_grp, *clone_grp = clone->group;
++	struct modp_group *new_grp, *clone_grp = clone->group;
+ 
+-  new_grp = malloc (sizeof *new_grp);
+-  assert (new_grp);
++	new_grp = malloc(sizeof *new_grp);
++	assert(new_grp);
+ 
+-  memcpy (new, clone, sizeof (struct group));
++	memcpy(new, clone, sizeof(struct group));
+ 
+-  new->group = new_grp;
+-  new_grp->p = gcry_mpi_copy (clone_grp->p);
+-  new_grp->gen = gcry_mpi_copy (clone_grp->gen);
++	new->group = new_grp;
++	new_grp->p = gcry_mpi_copy(clone_grp->p);
++	new_grp->gen = gcry_mpi_copy(clone_grp->gen);
+ 
+-  new_grp->a = gcry_mpi_new (clone->bits);
+-  new_grp->b = gcry_mpi_new (clone->bits);
+-  new_grp->c = gcry_mpi_new (clone->bits);
++	new_grp->a = gcry_mpi_new(clone->bits);
++	new_grp->b = gcry_mpi_new(clone->bits);
++	new_grp->c = gcry_mpi_new(clone->bits);
+ 
+-  new->gen = new_grp->gen;
+-  new->a = new_grp->a;
+-  new->b = new_grp->b;
+-  new->c = new_grp->c;
++	new->gen = new_grp->gen;
++	new->a = new_grp->a;
++	new->b = new_grp->b;
++	new->c = new_grp->c;
+ 
+-  return new;
++	return new;
+ }
+ 
+-void
+-modp_free (struct group *old)
++void modp_free(struct group *old)
+ {
+-  struct modp_group *grp = old->group;
++	struct modp_group *grp = old->group;
+ 
+-  gcry_mpi_release (grp->p);
+-  gcry_mpi_release (grp->gen);
+-  gcry_mpi_release (grp->a);
+-  gcry_mpi_release (grp->b);
+-  gcry_mpi_release (grp->c);
++	gcry_mpi_release(grp->p);
++	gcry_mpi_release(grp->gen);
++	gcry_mpi_release(grp->a);
++	gcry_mpi_release(grp->b);
++	gcry_mpi_release(grp->c);
+ 
+-  free (grp);
++	free(grp);
+ }
+ 
+-void
+-modp_init (struct group *group)
++void modp_init(struct group *group)
+ {
+-  struct modp_dscr *dscr = (struct modp_dscr *)group->group;
+-  struct modp_group *grp;
++	struct modp_dscr *dscr = (struct modp_dscr *)group->group;
++	struct modp_group *grp;
+ 
+-  grp = malloc (sizeof *grp);
+-  assert(grp);
++	grp = malloc(sizeof *grp);
++	assert(grp);
+ 
+-  group->bits = dscr->bits;
++	group->bits = dscr->bits;
+ 
+-  gcry_mpi_scan(&grp->p, GCRYMPI_FMT_HEX, dscr->prime, 0, NULL);
+-  gcry_mpi_scan(&grp->gen, GCRYMPI_FMT_HEX, dscr->gen, 0, NULL);
++	gcry_mpi_scan(&grp->p, GCRYMPI_FMT_HEX, dscr->prime, 0, NULL);
++	gcry_mpi_scan(&grp->gen, GCRYMPI_FMT_HEX, dscr->gen, 0, NULL);
+ 
+-  grp->a = gcry_mpi_new (group->bits);
+-  grp->b = gcry_mpi_new (group->bits);
+-  grp->c = gcry_mpi_new (group->bits);
++	grp->a = gcry_mpi_new(group->bits);
++	grp->b = gcry_mpi_new(group->bits);
++	grp->c = gcry_mpi_new(group->bits);
+ 
+-  group->gen = grp->gen;
+-  group->a = grp->a;
+-  group->b = grp->b;
+-  group->c = grp->c;
++	group->gen = grp->gen;
++	group->a = grp->a;
++	group->b = grp->b;
++	group->c = grp->c;
+ 
+-  group->group = grp;
++	group->group = grp;
+ }
+ 
+-int
+-modp_getlen (struct group *group)
++int modp_getlen(struct group *group)
+ {
+-  struct modp_group *grp = (struct modp_group *)group->group;
++	struct modp_group *grp = (struct modp_group *)group->group;
+ 
+-  return (gcry_mpi_get_nbits (grp->p) + 7) / 8;
++	return (gcry_mpi_get_nbits(grp->p) + 7) / 8;
+ }
+ 
+-void
+-modp_getraw (struct group *grp, gcry_mpi_t v, unsigned char *d)
++void modp_getraw(struct group *grp, gcry_mpi_t v, unsigned char *d)
+ {
+-  size_t l, l2;
+-  unsigned char *tmp;
+-  int ret;
+-  
+-  l = grp->getlen (grp);
+-  ret = gcry_mpi_aprint(GCRYMPI_FMT_STD, &tmp, &l2, v);
+-  memcpy(d, tmp + (l2-l), l);
+-  gcry_free(tmp);
++	size_t l, l2;
++	unsigned char *tmp;
++	int ret;
++
++	l = grp->getlen(grp);
++	ret = gcry_mpi_aprint(GCRYMPI_FMT_STD, &tmp, &l2, v);
++	memcpy(d, tmp + (l2 - l), l);
++	gcry_free(tmp);
+ #if 0
+-  {
+-	  char *p;
+-	  gcry_mpi_aprint(GCRYMPI_FMT_HEX, (void **)&p, NULL, v);
+-	  printf("export %d - %d(%d):\n%s\n", l, l2, ret, p);
+-  	  gcry_free(p);
+-  }
++	{
++		char *p;
++		gcry_mpi_aprint(GCRYMPI_FMT_HEX, (void **)&p, NULL, v);
++		printf("export %d - %d(%d):\n%s\n", l, l2, ret, p);
++		gcry_free(p);
++	}
+ #endif
+ }
+ 
+-int
+-modp_setraw (struct group *grp, gcry_mpi_t d, unsigned char *s, int l)
++int modp_setraw(struct group *grp, gcry_mpi_t d, unsigned char *s, int l)
+ {
+-  int i;
+-  
+-  grp = 0; /* unused */
+-  
+-  gcry_mpi_set_ui(d, 0);
+-  for (i = 0; i < l; i++)
+-    {
+-      gcry_mpi_mul_2exp (d, d, 8);
+-      gcry_mpi_add_ui (d, d, s[i]);
+-    }
++	int i;
++
++	grp = 0; /* unused */
++
++	gcry_mpi_set_ui(d, 0);
++	for (i = 0; i < l; i++) {
++		gcry_mpi_mul_2exp(d, d, 8);
++		gcry_mpi_add_ui(d, d, s[i]);
++	}
+ #if 0
+-  {
+-	  char *p;
+-	  gcry_mpi_aprint(GCRYMPI_FMT_HEX, (void **)&p, NULL, d);
+-	  printf("import %d:\n%s\n", l, p);
+-  	  gcry_free(p);
+-  }
++	{
++		char *p;
++		gcry_mpi_aprint(GCRYMPI_FMT_HEX, (void **)&p, NULL, d);
++		printf("import %d:\n%s\n", l, p);
++		gcry_free(p);
++	}
+ #endif
+-  return 0;
++	return 0;
+ }
+ 
+-int
+-modp_setrandom (struct group *grp, gcry_mpi_t d)
++int modp_setrandom(struct group *grp, gcry_mpi_t d)
+ {
+-  int i, l = grp->getlen (grp);
+-  uint32_t tmp = 0;
++	int i, l = grp->getlen(grp);
++	uint32_t tmp = 0;
+ 
+-  gcry_mpi_set_ui (d, 0);
++	gcry_mpi_set_ui(d, 0);
+ 
+-  for (i = 0; i < l; i++)
+-    {
+-      if (i % 4)
+-	gcry_randomize((unsigned char *)&tmp, sizeof(tmp), GCRY_WEAK_RANDOM);
++	for (i = 0; i < l; i++) {
++		if (i % 4)
++			gcry_randomize((unsigned char *)&tmp, sizeof(tmp), GCRY_WEAK_RANDOM);
+ 
+-      gcry_mpi_mul_2exp (d, d, 8);
+-      gcry_mpi_add_ui (d, d, tmp & 0xFF);
+-      tmp >>= 8;
+-    }
+-  return 0;
++		gcry_mpi_mul_2exp(d, d, 8);
++		gcry_mpi_add_ui(d, d, tmp & 0xFF);
++		tmp >>= 8;
++	}
++	return 0;
+ }
+ 
+-int
+-modp_operation (struct group *group, gcry_mpi_t d, gcry_mpi_t a, gcry_mpi_t e)
++int modp_operation(struct group *group, gcry_mpi_t d, gcry_mpi_t a, gcry_mpi_t e)
+ {
+-  struct modp_group *grp = (struct modp_group *)group->group;
++	struct modp_group *grp = (struct modp_group *)group->group;
+ 
+-  gcry_mpi_powm(d, a, e, grp->p);
+-  return 0;
++	gcry_mpi_powm(d, a, e, grp->p);
++	return 0;
+ }
+-
+diff -Nurd vpnc-0.2-rm+zomb.1/math_group.h new/math_group.h
+--- vpnc-0.2-rm+zomb.1/math_group.h	2003-10-25 01:49:22.000000000 +0200
++++ new/math_group.h	2004-06-10 11:19:53.000000000 +0200
+@@ -32,11 +32,11 @@
+  * This code was written under funding by Ericsson Radio Systems.
+  */
+ 
+-#ifndef _MATH_GROUP_H_
+-#define _MATH_GROUP_H_
++#ifndef __MATH_GROUP_H__
++#define __MATH_GROUP_H__
+ 
+ enum groups {
+-  MODP,				/* F_p, Z modulo a prime */
++	MODP, /* F_p, Z modulo a prime */
+ };
+ 
+ #define OAKLEY_GRP_1	1
+@@ -48,36 +48,36 @@
+  */
+ 
+ struct group {
+-  enum groups type;
+-  int id;			/* Group ID */
+-  int bits;			/* Number of key bits provided by this group */
+-  void *group;
+-  void *a, *b, *c, *d;
+-  void *gen;			/* Group Generator */
+-  int (*getlen) (struct group *);
+-  void (*getraw) (struct group *, void *, unsigned char *);
+-  int (*setraw) (struct group *, void *, unsigned char *, int);
+-  int (*setrandom) (struct group *, void *);
+-  int (*operation) (struct group *, void *, void *, void *);
++	enum groups type;
++	int id; /* Group ID */
++	int bits; /* Number of key bits provided by this group */
++	void *group;
++	void *a, *b, *c, *d;
++	void *gen; /* Group Generator */
++	int (*getlen) (struct group *);
++	void (*getraw) (struct group *, void *, unsigned char *);
++	int (*setraw) (struct group *, void *, unsigned char *, int);
++	int (*setrandom) (struct group *, void *);
++	int (*operation) (struct group *, void *, void *, void *);
+ };
+ 
+ /* Description of F_p for Boot-Strapping */
+ 
+ struct modp_dscr {
+-  int id;
+-  int bits;				/* Key Bits provided by this group */
+-  char *prime;				/* Prime */
+-  char *gen;				/* Generator */
++	int id;
++	int bits; /* Key Bits provided by this group */
++	char *prime; /* Prime */
++	char *gen; /* Generator */
+ };
+ 
+ /* Prototypes */
+ 
+-void group_init (void);
+-void group_free (struct group *);
+-struct group *group_get (int);
++void group_init(void);
++void group_free(struct group *);
++struct group *group_get(int);
+ 
+-void modp_free (struct group *);
+-struct group *modp_clone (struct group *, struct group *);
+-void modp_init (struct group *);
++void modp_free(struct group *);
++struct group *modp_clone(struct group *, struct group *);
++void modp_init(struct group *);
+ 
+ #endif /* _MATH_GROUP_H_ */
+diff -Nurd vpnc-0.2-rm+zomb.1/sysdep-bsd.c new/sysdep-bsd.c
+--- vpnc-0.2-rm+zomb.1/sysdep-bsd.c	2004-05-10 19:17:06.000000000 +0200
++++ new/sysdep-bsd.c	2004-05-30 14:32:32.000000000 +0200
+@@ -18,7 +18,7 @@
+ 
+ /*
+  * $Id: tun_dev.c,v 1.1.2.2 2000/11/20 08:15:53 maxk Exp $
+- */ 
++ */
+ 
+ #include <unistd.h>
+ #include <fcntl.h>
+@@ -39,34 +39,35 @@
+ /* 
+  * Allocate TUN device, returns opened fd. 
+  * Stores dev name in the first arg(must be large enough).
+- */  
++ */
+ int tun_open(char *dev)
+ {
+-    char tunname[14];
+-    int i, fd;
++	char tunname[14];
++	int i, fd;
+ 
+-    if( *dev ) {
+-       if (strncmp(dev, "tun", 3))
+-         error(1, 0, "error: arbitrary naming tunnel interface only supported on linux\n");
+-       sprintf(tunname, "/dev/%s", dev);
+-       return open(tunname, O_RDWR);
+-    }
++	if (*dev) {
++		if (strncmp(dev, "tun", 3))
++			error(1, 0,
++				"error: arbitrary naming tunnel interface only supported on linux\n");
++		sprintf(tunname, "/dev/%s", dev);
++		return open(tunname, O_RDWR);
++	}
+ 
+-    for(i=0; i < 255; i++){
+-       sprintf(tunname, "/dev/tun%d", i);
+-       /* Open device */
+-       if( (fd=open(tunname, O_RDWR)) > 0 ){
+-          sprintf(dev, "tun%d", i);
+-          return fd;
+-       }
+-    }
+-    return -1;
++	for (i = 0; i < 255; i++) {
++		sprintf(tunname, "/dev/tun%d", i);
++		/* Open device */
++		if ((fd = open(tunname, O_RDWR)) > 0) {
++			sprintf(dev, "tun%d", i);
++			return fd;
++		}
++	}
++	return -1;
+ }
+ 
+ int tun_close(int fd, char *dev)
+ {
+-    dev = NULL; /*unused*/
+-    return close(fd);
++	dev = NULL; /*unused */
++	return close(fd);
+ }
+ 
+ #ifdef NEW_TUN
+@@ -82,52 +83,52 @@
+ /* Read/write frames from TUN device */
+ int tun_write(int fd, char *buf, int len)
+ {
+-    char *data;
+-    struct tun_data tun;
+-    
+-    if (len > (int)sizeof(tun.data))
+-	return -1;
+-    
+-    memcpy(tun.data, buf, len);
+-    tun.header.family = htonl(AF_INET);
+-    len += (sizeof(tun) - sizeof(tun.data));
+-    data = (char *)&tun;
+-    
+-    return write(fd, data, len) - (sizeof(tun) - sizeof(tun.data));
++	char *data;
++	struct tun_data tun;
++
++	if (len > (int)sizeof(tun.data))
++		return -1;
++
++	memcpy(tun.data, buf, len);
++	tun.header.family = htonl(AF_INET);
++	len += (sizeof(tun) - sizeof(tun.data));
++	data = (char *)&tun;
++
++	return write(fd, data, len) - (sizeof(tun) - sizeof(tun.data));
+ }
+ 
+ int tun_read(int fd, char *buf, int len)
+ {
+-    struct tun_data tun;
+-    char *data;
+-    size_t sz;
+-    int pack;
+-    
+-    data = (char *)&tun;
+-    sz = sizeof(tun);
+-    pack = read(fd, data, sz);
+-    if (pack == -1)
+-	    return -1;
+-    
+-    pack -= sz - sizeof(tun.data);
+-    if (pack > len)
+-	    pack = len; /* truncate paket */
+-    
+-    memcpy(buf, tun.data, pack);
+-    
+-    return pack;
++	struct tun_data tun;
++	char *data;
++	size_t sz;
++	int pack;
++
++	data = (char *)&tun;
++	sz = sizeof(tun);
++	pack = read(fd, data, sz);
++	if (pack == -1)
++		return -1;
++
++	pack -= sz - sizeof(tun.data);
++	if (pack > len)
++		pack = len; /* truncate paket */
++
++	memcpy(buf, tun.data, pack);
++
++	return pack;
+ }
+ 
+ #else
+ 
+ int tun_write(int fd, char *buf, int len)
+ {
+-    return write(fd, buf, len);
++	return write(fd, buf, len);
+ }
+ 
+ int tun_read(int fd, char *buf, int len)
+ {
+-    return read(fd, buf, len);
++	return read(fd, buf, len);
+ }
+ #endif
+ 
+@@ -141,8 +142,8 @@
+ 
+ void error(int status, int errornum, const char *fmt, ...)
+ {
+-	char   *buf2;
+-	va_list        ap;
++	char *buf2;
++	va_list ap;
+ 
+ 	va_start(ap, fmt);
+ 	vasprintf(&buf2, fmt, ap);
+@@ -151,12 +152,12 @@
+ 	if (errornum)
+ 		fprintf(stderr, ": %s\n", strerror(errornum));
+ 	free(buf2);
+-	
++
+ 	if (status)
+ 		exit(status);
+ }
+ 
+-int getline(char **line, size_t *length, FILE *stream)
++int getline(char **line, size_t * length, FILE * stream)
+ {
+ 	char *tmpline;
+ 	size_t len;
+diff -Nurd vpnc-0.2-rm+zomb.1/sysdep.h new/sysdep.h
+--- vpnc-0.2-rm+zomb.1/sysdep.h	2004-05-13 23:04:45.000000000 +0200
++++ new/sysdep.h	2004-05-30 14:32:32.000000000 +0200
+@@ -14,7 +14,7 @@
+ #include <error.h>
+ #else
+ extern void error(int fd, int errorno, const char *fmt, ...);
+-extern int getline(char **line, size_t *length, FILE *stream);
++extern int getline(char **line, size_t * length, FILE * stream);
+ #endif
+ 
+ #if defined(__sun__)
+diff -Nurd vpnc-0.2-rm+zomb.1/sysdep-linux.c new/sysdep-linux.c
+--- vpnc-0.2-rm+zomb.1/sysdep-linux.c	2004-05-02 04:28:25.000000000 +0200
++++ new/sysdep-linux.c	2004-05-30 14:32:32.000000000 +0200
+@@ -18,7 +18,7 @@
+ 
+ /*
+  * $Id: tun_dev.c,v 1.1.2.2 2000/11/20 08:15:53 maxk Exp $
+- */ 
++ */
+ 
+ #include <unistd.h>
+ #include <fcntl.h>
+@@ -38,71 +38,73 @@
+ /* 
+  * Allocate TUN device, returns opened fd. 
+  * Stores dev name in the first arg(must be large enough).
+- */  
++ */
+ #ifdef IFF_TUN
+ int tun_open(char *dev)
+ {
+-    struct ifreq ifr;
+-    int fd, err;
++	struct ifreq ifr;
++	int fd, err;
+ 
+-    if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
+-       error(0, errno, "can't open /dev/net/tun, check that it is either device char 10 200 or (with DevFS) a symlink to ../misc/net/tun (not misc/net/tun!!!)");
+-       return -1;
+-    }
++	if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
++		error(0, errno,
++			"can't open /dev/net/tun, check that it is either device char 10 200 or (with DevFS) a symlink to ../misc/net/tun (not misc/net/tun)");
++		return -1;
++	}
+ 
+-    memset(&ifr, 0, sizeof(ifr));
+-    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+-    if( *dev )
+-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
++	memset(&ifr, 0, sizeof(ifr));
++	ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
++	if (*dev)
++		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ 
+-    if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
+-       close(fd);
+-       return err;
+-    } 
+-    strcpy(dev, ifr.ifr_name);
+-    return fd;
++	if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
++		close(fd);
++		return err;
++	}
++	strcpy(dev, ifr.ifr_name);
++	return fd;
+ }
+ #else
+ int tun_open(char *dev)
+ {
+-    char tunname[14];
+-    int i, fd;
++	char tunname[14];
++	int i, fd;
+ 
+-    if( *dev ) {
+-       if (strncmp(dev, "tun", 3))
+-         error(1, 0, "error: arbitrary naming tunnel interface is not supported in this version\n");
+-       sprintf(tunname, "/dev/%s", dev);
+-       return open(tunname, O_RDWR);
+-    }
++	if (*dev) {
++		if (strncmp(dev, "tun", 3))
++			error(1, 0,
++				"error: arbitrary naming tunnel interface is not supported in this version\n");
++		sprintf(tunname, "/dev/%s", dev);
++		return open(tunname, O_RDWR);
++	}
+ 
+-    for(i=0; i < 255; i++){
+-       sprintf(tunname, "/dev/tun%d", i);
+-       /* Open device */
+-       if( (fd=open(tunname, O_RDWR)) > 0 ){
+-          sprintf(dev, "tun%d", i);
+-          return fd;
+-       }
+-    }
+-    return -1;
++	for (i = 0; i < 255; i++) {
++		sprintf(tunname, "/dev/tun%d", i);
++		/* Open device */
++		if ((fd = open(tunname, O_RDWR)) > 0) {
++			sprintf(dev, "tun%d", i);
++			return fd;
++		}
++	}
++	return -1;
+ }
+ 
+ #endif /* New driver support */
+ 
+ int tun_close(int fd, char *dev)
+ {
+-    dev = NULL; /*unused*/
+-    return close(fd);
++	dev = NULL; /*unused */
++	return close(fd);
+ }
+ 
+ /* Read/write frames from TUN device */
+ int tun_write(int fd, char *buf, int len)
+ {
+-    return write(fd, buf, len);
++	return write(fd, buf, len);
+ }
+ 
+ int tun_read(int fd, char *buf, int len)
+ {
+-    return read(fd, buf, len);
++	return read(fd, buf, len);
+ }
+ 
+ /***********************************************************************/
+@@ -112,4 +114,3 @@
+ {
+ 	return "ifconfig $TUNDEV inet $INTERNAL_IP4_ADDRESS pointopoint $INTERNAL_IP4_ADDRESS netmask 255.255.255.255 mtu 1412 up";
+ }
+-
+diff -Nurd vpnc-0.2-rm+zomb.1/sysdep-svr4.c new/sysdep-svr4.c
+--- vpnc-0.2-rm+zomb.1/sysdep-svr4.c	2004-05-08 17:47:28.000000000 +0200
++++ new/sysdep-svr4.c	2004-05-30 14:32:32.000000000 +0200
+@@ -18,7 +18,7 @@
+ 
+ /*
+  * $Id: tun_dev.c,v 1.2.2.2 2000/11/20 08:15:53 maxk Exp $
+- */ 
++ */
+ 
+ #include <unistd.h>
+ #include <fcntl.h>
+@@ -49,117 +49,118 @@
+ /* 
+  * Allocate TUN device, returns opened fd. 
+  * Stores dev name in the first arg(must be large enough).
+- */  
++ */
+ int tun_open(char *dev)
+ {
+-    int tun_fd, if_fd, ppa = -1;
+-    struct ifreq ifr;
+-    char *ptr;
++	int tun_fd, if_fd, ppa = -1;
++	struct ifreq ifr;
++	char *ptr;
+ 
+-    if( *dev ){
+-       ptr = dev;	
+-       while( *ptr && !isdigit((int)*ptr) ) ptr++; 
+-       ppa = atoi(ptr);
+-    }
++	if (*dev) {
++		ptr = dev;
++		while (*ptr && !isdigit((int)*ptr))
++			ptr++;
++		ppa = atoi(ptr);
++	}
+ 
+-    if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
+-       syslog(LOG_ERR, "Can't open /dev/ip");
+-       return -1;
+-    }
++	if ((ip_fd = open("/dev/udp", O_RDWR, 0)) < 0) {
++		syslog(LOG_ERR, "Can't open /dev/ip");
++		return -1;
++	}
+ 
+-    if( (tun_fd = open("/dev/tun", O_RDWR, 0)) < 0){
+-       syslog(LOG_ERR, "Can't open /dev/tun");
+-       return -1;
+-    }
++	if ((tun_fd = open("/dev/tun", O_RDWR, 0)) < 0) {
++		syslog(LOG_ERR, "Can't open /dev/tun");
++		return -1;
++	}
+ 
+-    /* Assign a new PPA and get its unit number. */
+-    if( (ppa = ioctl(tun_fd, TUNNEWPPA, ppa)) < 0){
+-       syslog(LOG_ERR, "Can't assign new interface");
+-       return -1;
+-    }
++	/* Assign a new PPA and get its unit number. */
++	if ((ppa = ioctl(tun_fd, TUNNEWPPA, ppa)) < 0) {
++		syslog(LOG_ERR, "Can't assign new interface");
++		return -1;
++	}
+ 
+-    if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
+-       syslog(LOG_ERR, "Can't open /dev/tun (2)");
+-       return -1;
+-    }
+-    if(ioctl(if_fd, I_PUSH, "ip") < 0){
+-       syslog(LOG_ERR, "Can't push IP module");
+-       return -1;
+-    }
++	if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) {
++		syslog(LOG_ERR, "Can't open /dev/tun (2)");
++		return -1;
++	}
++	if (ioctl(if_fd, I_PUSH, "ip") < 0) {
++		syslog(LOG_ERR, "Can't push IP module");
++		return -1;
++	}
+ 
+-    /* Assign ppa according to the unit number returned by tun device */
+-    if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
+-       syslog(LOG_ERR, "Can't set PPA %d", ppa);
+-       return -1;
+-    }
+-    if( (muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0){
+-       syslog(LOG_ERR, "Can't link TUN device to IP");
+-       return -1;
+-    }
+-    close(if_fd);    
++	/* Assign ppa according to the unit number returned by tun device */
++	if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) {
++		syslog(LOG_ERR, "Can't set PPA %d", ppa);
++		return -1;
++	}
++	if ((muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0) {
++		syslog(LOG_ERR, "Can't link TUN device to IP");
++		return -1;
++	}
++	close(if_fd);
+ 
+-    sprintf(dev, "tun%d", ppa);
++	sprintf(dev, "tun%d", ppa);
+ 
+-    memset(&ifr, 0, sizeof(ifr));
+-    strcpy(ifr.ifr_name, dev);
+-    ifr.ifr_ip_muxid = muxid;
++	memset(&ifr, 0, sizeof(ifr));
++	strcpy(ifr.ifr_name, dev);
++	ifr.ifr_ip_muxid = muxid;
+ 
+-    if( ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0 ){
+-       ioctl(ip_fd, I_PUNLINK, muxid);
+-       syslog(LOG_ERR, "Can't set multiplexor id");
+-       return -1;
+-    }
++	if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
++		ioctl(ip_fd, I_PUNLINK, muxid);
++		syslog(LOG_ERR, "Can't set multiplexor id");
++		return -1;
++	}
+ 
+-    return tun_fd;
++	return tun_fd;
+ }
+ 
+ /* 
+  * Close TUN device. 
+- */  
++ */
+ int tun_close(int fd, char *dev)
+ {
+-    struct ifreq ifr;
+-
+-    memset(&ifr, 0, sizeof(ifr));
+-    strcpy(ifr.ifr_name, dev);
+-    if( ioctl(ip_fd, SIOCGIFFLAGS, &ifr) < 0 ){
+-       syslog(LOG_ERR, "Can't get iface flags");
+-       return 0;
+-    }
++	struct ifreq ifr;
+ 
++	memset(&ifr, 0, sizeof(ifr));
++	strcpy(ifr.ifr_name, dev);
++	if (ioctl(ip_fd, SIOCGIFFLAGS, &ifr) < 0) {
++		syslog(LOG_ERR, "Can't get iface flags");
++		return 0;
++	}
+ #if 0
+-    if( ioctl(ip_fd, SIOCGIFMUXID, &ifr) < 0 ){
+-       syslog(LOG_ERR, "Can't get multiplexor id");
+-       return 0;
+-    }
+-    muxid = ifr.ifr_ip_muxid;
++	if (ioctl(ip_fd, SIOCGIFMUXID, &ifr) < 0) {
++		syslog(LOG_ERR, "Can't get multiplexor id");
++		return 0;
++	}
++	muxid = ifr.ifr_ip_muxid;
+ #endif
+ 
+-    if( ioctl(ip_fd, I_PUNLINK, muxid) < 0 ){
+-       syslog(LOG_ERR, "Can't unlink interface");
+-       return 0;
+-    }
++	if (ioctl(ip_fd, I_PUNLINK, muxid) < 0) {
++		syslog(LOG_ERR, "Can't unlink interface");
++		return 0;
++	}
+ 
+-    close(ip_fd); close(fd);
+-    return 0;
++	close(ip_fd);
++	close(fd);
++	return 0;
+ }
+ 
+ int tun_write(int fd, char *buf, int len)
+ {
+-    struct strbuf sbuf;
+-    sbuf.len = len;      
+-    sbuf.buf = buf;      
+-    return putmsg(fd, NULL, &sbuf, 0) >=0 ? sbuf.len : -1;
++	struct strbuf sbuf;
++	sbuf.len = len;
++	sbuf.buf = buf;
++	return putmsg(fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1;
+ }
+ 
+ int tun_read(int fd, char *buf, int len)
+ {
+-    struct strbuf sbuf;
+-    int f = 0;
++	struct strbuf sbuf;
++	int f = 0;
+ 
+-    sbuf.maxlen = len;      
+-    sbuf.buf = buf;      
+-    return getmsg(fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
++	sbuf.maxlen = len;
++	sbuf.buf = buf;
++	return getmsg(fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
+ }
+ 
+ /***********************************************************************/
+@@ -174,14 +175,14 @@
+ {
+ 	int ret;
+ 	char *strbuf;
+-	
++
+ 	ret = vsnprintf(NULL, 0, fmt, ap);
+-	strbuf = (char *)malloc(ret+1);
++	strbuf = (char *)malloc(ret + 1);
+ 	if (strbuf == NULL) {
+ 		errno = ENOMEM;
+ 		ret = -1;
+ 	}
+-	vsnprintf(strbuf, ret+1, fmt, ap);
++	vsnprintf(strbuf, ret + 1, fmt, ap);
+ 	*strp = strbuf;
+ 	return ret;
+ }
+@@ -190,18 +191,18 @@
+ {
+ 	int ret;
+ 	va_list ap;
+-	
++
+ 	va_start(ap, fmt);
+ 	ret = vasprintf(strp, fmt, ap);
+ 	va_end(ap);
+-	
++
+ 	return ret;
+ }
+ 
+ void error(int status, int errornum, const char *fmt, ...)
+ {
+-	char   *buf2;
+-	va_list        ap;
++	char *buf2;
++	va_list ap;
+ 
+ 	va_start(ap, fmt);
+ 	vasprintf(&buf2, fmt, ap);
+@@ -210,12 +211,12 @@
+ 	if (errornum)
+ 		fprintf(stderr, ": %s\n", strerror(errornum));
+ 	free(buf2);
+-	
++
+ 	if (status)
+ 		exit(status);
+ }
+ 
+-int getline(char **line, size_t *length, FILE *stream)
++int getline(char **line, size_t * length, FILE * stream)
+ {
+ 	char tmpline[512];
+ 	size_t len;
+@@ -243,38 +244,38 @@
+ void unsetenv(const char *name)
+ {
+ 	int i, len;
+-	
++
+ 	len = strlen(name);
+ 	for (i = 0; environ[i]; i++)
+ 		if (!strncmp(name, environ[i], len))
+ 			if (environ[i][len] == '=')
+ 				break;
+-	
+-	for (; environ[i] && environ[i+1]; i++)
+-		environ[i] = environ[i+1];
++
++	for (; environ[i] && environ[i + 1]; i++)
++		environ[i] = environ[i + 1];
+ }
+ 
+ int setenv(const char *name, const char *value, int overwrite)
+ {
+ 	int ret;
+ 	char *newenv;
+-	
++
+ 	if (overwrite == 0)
+ 		if (getenv(name) != NULL)
+ 			return 0;
+-	
++
+ 	newenv = malloc(strlen(name) + 1 + strlen(value) + 1);
+ 	if (newenv == NULL)
+ 		return -1;
+-	
++
+ 	*newenv = '\0';
+ 	strcat(newenv, name);
+ 	strcat(newenv, "=");
+ 	strcat(newenv, value);
+-	
++
+ 	ret = putenv(newenv);
+ 	if (ret == -1)
+ 		free(newenv);
+-	
++
+ 	return ret;
+ }
+diff -Nurd vpnc-0.2-rm+zomb.1/TODO new/TODO
+--- vpnc-0.2-rm+zomb.1/TODO	2004-05-13 17:43:29.000000000 +0200
++++ new/TODO	2004-05-23 13:45:53.000000000 +0200
+@@ -66,7 +66,7 @@
+ 
+ * DONE XAUTH Domain: (empty)
+ 
+-* svn-Repository
++* DONE svn-Repository
+ 
+ * implement udp transport NAT-T
+ 
+diff -Nurd vpnc-0.2-rm+zomb.1/tunip.c new/tunip.c
+--- vpnc-0.2-rm+zomb.1/tunip.c	2004-05-13 22:38:46.000000000 +0200
++++ new/tunip.c	2004-06-10 11:19:53.000000000 +0200
+@@ -71,6 +71,7 @@
+ 
+ #include <gcrypt.h>
+ #include "sysdep.h"
++#include "config.h"
+ #include "vpnc.h"
+ 
+ #define max(a,b)	((a)>(b)?(a):(b))
+@@ -78,88 +79,84 @@
+ #define UDP_PORT	2001
+ 
+ struct sa_desc {
+-    struct sa_desc *next;
++	struct sa_desc *next;
+ 
+-    struct sockaddr_in init;	/* initial and fallback remote address */
+-    struct sockaddr_in dest;	/* current remote address */
+-    struct sockaddr_in source;	/* local socket address we send packets from */
+-    unsigned char use_fallback;	/* use initial address as fallback? */
+-    unsigned char use_dest;	/* is dest address known yet? */
++	struct sockaddr_in init; /* initial and fallback remote address */
++	struct sockaddr_in dest; /* current remote address */
++	struct sockaddr_in source; /* local socket address we send packets from */
++	unsigned char use_fallback; /* use initial address as fallback? */
++	unsigned char use_dest; /* is dest address known yet? */
+ 
+-    unsigned long spi;		/* security parameters index */
+-    unsigned long seq_id;	/* for replay protection (not implemented) */
++	unsigned long spi; /* security parameters index */
++	unsigned long seq_id; /* for replay protection (not implemented) */
+ 
+-    /* Encryption key */
+-    const unsigned char *enc_secret;
+-    unsigned int enc_secret_size;
+-    unsigned int ivlen;
+-    /* Preprocessed encryption key */
+-    gcry_cipher_hd_t cry_ctx;
+-    int cry_algo;
++	/* Encryption key */
++	const unsigned char *enc_secret;
++	unsigned int enc_secret_size;
++	unsigned int ivlen;
++	/* Preprocessed encryption key */
++	gcry_cipher_hd_t cry_ctx;
++	int cry_algo;
+ 
+-    /* Authentication secret */
+-    const unsigned char *auth_secret;
+-    unsigned int auth_secret_size;
+-    /* Authentication method to use, or NULL */
+-    int md_algo;
++	/* Authentication secret */
++	const unsigned char *auth_secret;
++	unsigned int auth_secret_size;
++	/* Authentication method to use, or NULL */
++	int md_algo;
+ 
+-    /* Encapsulation method to use to send packets */
+-    struct encap_method *em;
++	/* Encapsulation method to use to send packets */
++	struct encap_method *em;
+ 
+-    /* timeout counters */
+-    time_t last_packet_sent, last_packet_recv, last_checkifaddr;
++	/* timeout counters */
++	time_t last_packet_sent, last_packet_recv, last_checkifaddr;
+ };
+ 
+ struct peer_desc {
+-    struct sa_desc *local_sa, *remote_sa;
+-    int tun_fd;		/* file descriptor for associated tunnel device */
++	struct sa_desc *local_sa, *remote_sa;
++	int tun_fd; /* file descriptor for associated tunnel device */
+ };
+ 
+ /* A real ESP header (RFC 2406) */
+ typedef struct esp_encap_header {
+-    unsigned long spi;			/* security parameters index */
+-    unsigned long seq_id;		/* sequence id (unimplemented) */
+-    /* variable-length payload data + padding */
+-    /* unsigned char next_header */
+-    /* optional auth data */
++	unsigned long spi; /* security parameters index */
++	unsigned long seq_id; /* sequence id (unimplemented) */
++	/* variable-length payload data + padding */
++	/* unsigned char next_header */
++	/* optional auth data */
+ } esp_encap_header_t;
+ 
+ struct encap_method {
+-    int fd;			/* file descriptor for relevant socket */
+-    unsigned char *name;
++	int fd; /* file descriptor for relevant socket */
++	unsigned char *name;
+ 
+-    int fixed_header_size;
++	int fixed_header_size;
+ 
+-    /* Description of the packet being processed */
+-    unsigned char *buf;
+-    unsigned int bufsize, bufpayload, var_header_size;
+-    int buflen;
+-    struct sockaddr_in from; int fromlen;
++	/* Description of the packet being processed */
++	unsigned char *buf;
++	unsigned int bufsize, bufpayload, var_header_size;
++	int buflen;
++	struct sockaddr_in from;
++	int fromlen;
+ 
+-    int (*recv)(struct encap_method *encap,
+-		unsigned char *buf, unsigned int bufsize,
+-		struct sockaddr_in *from);
+-    struct peer_desc *(*peer_find)(struct encap_method *encap);
+-    void (*send_peer)(struct encap_method *encap,
+-		      struct peer_desc *peer,
+-		      unsigned char *buf, unsigned int bufsize);
+-    int (*recv_peer)(struct encap_method *encap,
+-		     struct peer_desc *peer);
++	int (*recv) (struct encap_method * encap,
++		unsigned char *buf, unsigned int bufsize, struct sockaddr_in * from);
++	struct peer_desc *(*peer_find) (struct encap_method * encap);
++	void (*send_peer) (struct encap_method * encap,
++		struct peer_desc * peer, unsigned char *buf, unsigned int bufsize);
++	int (*recv_peer) (struct encap_method * encap, struct peer_desc * peer);
+ };
+ 
+ /* Forward decl */
+ void encap_esp_send_peer(struct encap_method *encap,
+-			 struct peer_desc *peer,
+-			 unsigned char *buf, unsigned int bufsize);
++	struct peer_desc *peer, unsigned char *buf, unsigned int bufsize);
+ struct peer_desc *peer_find(unsigned long spi, struct encap_method *encap);
+-int encap_esp_recv_peer(struct encap_method *encap,
+-			struct peer_desc *peer);
++int encap_esp_recv_peer(struct encap_method *encap, struct peer_desc *peer);
+ 
+ /* Yuck! Global variables... */
+ 
+ #define MAX_HEADER 64
+ #define MAX_PACKET 4096
+-unsigned char buf[MAX_HEADER+MAX_PACKET];
++unsigned char buf[MAX_HEADER + MAX_PACKET];
+ 
+ struct peer_desc vpnpeer;
+ 
+@@ -183,8 +180,7 @@
+  * in_cksum --
+  *	Checksum routine for Internet Protocol family headers (C Version)
+  */
+-u_short
+-in_cksum(addr, len)
++u_short in_cksum(addr, len)
+ 	u_short *addr;
+ 	int len;
+ {
+@@ -198,79 +194,76 @@
+ 	 * sequential 16 bit words to it, and at the end, fold back all the
+ 	 * carry bits from the top 16 bits into the lower 16 bits.
+ 	 */
+-	while (nleft > 1)  {
++	while (nleft > 1) {
+ 		sum += *w++;
+ 		nleft -= 2;
+ 	}
+ 
+ 	/* mop up an odd byte, if necessary */
+ 	if (nleft == 1) {
+-		*(u_char *)(&answer) = *(u_char *)w ;
++		*(u_char *) (&answer) = *(u_char *) w;
+ 		sum += answer;
+ 	}
+ 
+ 	/* add back carry outs from top 16 bits to low 16 bits */
+-	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
+-	sum += (sum >> 16);			/* add carry */
+-	answer = ~sum;				/* truncate to 16 bits */
+-	return(answer);
++	sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
++	sum += (sum >> 16); /* add carry */
++	answer = ~sum; /* truncate to 16 bits */
++	return (answer);
+ }
+ 
+ /*
+  * Decapsulate from a raw IP packet
+  */
+ int encap_rawip_recv(struct encap_method *encap,
+-		     unsigned char *buf, unsigned int bufsize,
+-		     struct sockaddr_in *from)
++	unsigned char *buf, unsigned int bufsize, struct sockaddr_in *from)
+ {
+-    int r;
+-    struct ip *p = (struct ip *)buf;
+-
+-    encap->fromlen = sizeof(encap->from);
++	int r;
++	struct ip *p = (struct ip *)buf;
+ 
+-    r = recvfrom(encap->fd, buf, bufsize, 0,
+-		 (struct sockaddr *)&encap->from, &encap->fromlen);
+-    if (r == -1) {
+-	syslog(LOG_ERR, "recvfrom: %m");
+-	return -1;
+-    }
+-    if (r < (p->ip_hl << 2)+encap->fixed_header_size) {
+-        syslog(LOG_ALERT, "packet too short from %s",
+-		inet_ntoa(encap->from.sin_addr));
+-	return -1;
+-    }
++	encap->fromlen = sizeof(encap->from);
+ 
++	r = recvfrom(encap->fd, buf, bufsize, 0, (struct sockaddr *)&encap->from, &encap->fromlen);
++	if (r == -1) {
++		syslog(LOG_ERR, "recvfrom: %m");
++		return -1;
++	}
++	if (r < (p->ip_hl << 2) + encap->fixed_header_size) {
++		syslog(LOG_ALERT, "packet too short from %s", inet_ntoa(encap->from.sin_addr));
++		return -1;
++	}
+ #if 0
+-    printf("raw got %d bytes\n", r);
+-    for (i = 0; i < r; i++) {
+-	printf(" %02x", buf[i]);
+-	if ((i & 15) == 15) printf("\n");
+-    }
+-    printf("\n");
++	printf("raw got %d bytes\n", r);
++	for (i = 0; i < r; i++) {
++		printf(" %02x", buf[i]);
++		if ((i & 15) == 15)
++			printf("\n");
++	}
++	printf("\n");
+ #endif
+ 
+ #ifdef NEED_IPID_SWAP
+-    p->ip_id = htons(p->ip_id);
++	p->ip_id = htons(p->ip_id);
+ #endif
+ #ifdef NEED_IPLEN_FIX
+-    p->ip_len = r;
++	p->ip_len = r;
+ #else
+-    p->ip_len = ntohs(r);
++	p->ip_len = ntohs(r);
+ #endif
+ 
+-    encap->buf = buf;
+-    encap->buflen = r;
+-    encap->bufpayload = (p->ip_hl << 2);
+-    encap->bufsize = bufsize;
+-    *from = encap->from;
+-    return r;
++	encap->buf = buf;
++	encap->buflen = r;
++	encap->bufpayload = (p->ip_hl << 2);
++	encap->bufsize = bufsize;
++	*from = encap->from;
++	return r;
+ }
+ 
+ struct peer_desc *encap_esp_peer_find(struct encap_method *encap)
+ {
+-    esp_encap_header_t *eh;
+-    eh = (esp_encap_header_t *)(encap->buf + encap->bufpayload);
+-    return peer_find(ntohl(eh->spi), encap);
++	esp_encap_header_t *eh;
++	eh = (esp_encap_header_t *) (encap->buf + encap->bufpayload);
++	return peer_find(ntohl(eh->spi), encap);
+ }
+ 
+ /*
+@@ -278,13 +271,11 @@
+  */
+ int encap_any_decap(struct encap_method *encap)
+ {
+-    encap->buflen
+-      -= encap->bufpayload+encap->fixed_header_size+encap->var_header_size;
+-    encap->buf
+-      += encap->bufpayload+encap->fixed_header_size+encap->var_header_size;
+-    if (encap->buflen == 0)
+-        return 0;
+-    return 1;
++	encap->buflen -= encap->bufpayload + encap->fixed_header_size + encap->var_header_size;
++	encap->buf += encap->bufpayload + encap->fixed_header_size + encap->var_header_size;
++	if (encap->buflen == 0)
++		return 0;
++	return 1;
+ }
+ 
+ /*
+@@ -292,42 +283,42 @@
+  */
+ int tun_send_ip(struct encap_method *encap, int fd)
+ {
+-    int sent;
++	int sent;
+ 
+-    sent = tun_write(fd, encap->buf, encap->buflen);
+-    if (sent != encap->buflen)
+-        syslog(LOG_ERR, "truncated in: %d -> %d\n", encap->buflen, sent);
+-    return 1;
++	sent = tun_write(fd, encap->buf, encap->buflen);
++	if (sent != encap->buflen)
++		syslog(LOG_ERR, "truncated in: %d -> %d\n", encap->buflen, sent);
++	return 1;
+ }
+ 
+ int encap_esp_new(struct encap_method *encap, unsigned char proto)
+ {
+ #ifdef IP_HDRINCL
+-    int hincl = 1;
++	int hincl = 1;
+ #endif
+ 
+-    encap->fd = socket(PF_INET, SOCK_RAW, proto);
++	encap->fd = socket(PF_INET, SOCK_RAW, proto);
+ 
+-    if (encap->fd == -1) {
+-	perror("socket(SOCK_RAW)");
+-	return -1;
+-    }
++	if (encap->fd == -1) {
++		perror("socket(SOCK_RAW)");
++		return -1;
++	}
+ #ifdef IP_HDRINCL
+-    if (setsockopt(encap->fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl))
+-	== -1) {
+-        perror("setsockopt(IP_HDRINCL)");
+-	close(encap->fd);
+-	return -1;
+-    }
++	if (setsockopt(encap->fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl))
++		== -1) {
++		perror("setsockopt(IP_HDRINCL)");
++		close(encap->fd);
++		return -1;
++	}
+ #endif
+-    encap->name = "ipesp";
+-    encap->recv = encap_rawip_recv;
+-    encap->peer_find = encap_esp_peer_find;
+-    encap->send_peer = encap_esp_send_peer;
+-    encap->recv_peer = encap_esp_recv_peer;
+-    encap->fixed_header_size = sizeof(esp_encap_header_t);
+-    encap->var_header_size = 0;
+-    return 0;
++	encap->name = "ipesp";
++	encap->recv = encap_rawip_recv;
++	encap->peer_find = encap_esp_peer_find;
++	encap->send_peer = encap_esp_send_peer;
++	encap->recv_peer = encap_esp_recv_peer;
++	encap->fixed_header_size = sizeof(esp_encap_header_t);
++	encap->var_header_size = 0;
++	return 0;
+ }
+ 
+ /*
+@@ -336,41 +327,40 @@
+  */
+ int find_local_addr(struct sockaddr_in *dest, struct sockaddr_in *source)
+ {
+-    int addrlen;
+-    struct sockaddr_in dest_socket;
+-    int fd;
++	int addrlen;
++	struct sockaddr_in dest_socket;
++	int fd;
+ 
+-    fd = socket(PF_INET, SOCK_DGRAM, 0);
+-    if (fd == -1) {
+-	syslog(LOG_ERR, "socket: %m");
+-	return -1;
+-    }
++	fd = socket(PF_INET, SOCK_DGRAM, 0);
++	if (fd == -1) {
++		syslog(LOG_ERR, "socket: %m");
++		return -1;
++	}
+ 
+-    memset(&dest_socket, 0, sizeof(dest_socket));
++	memset(&dest_socket, 0, sizeof(dest_socket));
+ 
+-    dest_socket.sin_family = AF_INET;
++	dest_socket.sin_family = AF_INET;
+ #ifdef HAVE_SA_LEN
+-    dest_socket.sin_len = sizeof(dest_socket);
++	dest_socket.sin_len = sizeof(dest_socket);
+ #endif
+-    dest_socket.sin_addr = dest->sin_addr;
+-    dest_socket.sin_port = htons(4444);
++	dest_socket.sin_addr = dest->sin_addr;
++	dest_socket.sin_port = htons(4444);
+ 
+-    if (connect(fd,
+-		(struct sockaddr *)&dest_socket, sizeof(dest_socket)) == -1) {
+-	syslog(LOG_ERR, "connect: %m");
+-	close(fd);
+-	return -1;
+-    }
++	if (connect(fd, (struct sockaddr *)&dest_socket, sizeof(dest_socket)) == -1) {
++		syslog(LOG_ERR, "connect: %m");
++		close(fd);
++		return -1;
++	}
+ 
+-    addrlen = sizeof(*source);
++	addrlen = sizeof(*source);
+ 
+-    if (getsockname(fd, (struct sockaddr *)source, &addrlen) == -1) {
+-	syslog(LOG_ERR, "getsockname: %m");
++	if (getsockname(fd, (struct sockaddr *)source, &addrlen) == -1) {
++		syslog(LOG_ERR, "getsockname: %m");
++		close(fd);
++		return -1;
++	}
+ 	close(fd);
+-	return -1;
+-    }
+-    close(fd);
+-    return 0;
++	return 0;
+ }
+ 
+ /*
+@@ -379,24 +369,23 @@
+  */
+ int update_sa_addr(struct sa_desc *p)
+ {
+-    struct sockaddr_in new_addr;
++	struct sockaddr_in new_addr;
+ 
+-    if (find_local_addr(&p->dest, &new_addr) == -1) {
+-	syslog(LOG_ALERT,
+-		"can't find a local address for packets to %s",
+-		inet_ntoa(p->dest.sin_addr));
+-	return -1;
+-    }
+-    if (new_addr.sin_addr.s_addr != p->source.sin_addr.s_addr) {
+-	char addr1[16];
+-	p->source.sin_addr = new_addr.sin_addr;
+-	strcpy(addr1, inet_ntoa(p->dest.sin_addr));
+-	syslog(LOG_NOTICE,
+-		"local address for %s is %s", addr1,
+-		inet_ntoa(p->source.sin_addr));
+-	return 1;
+-    }
+-    return 0;
++	if (find_local_addr(&p->dest, &new_addr) == -1) {
++		syslog(LOG_ALERT,
++			"can't find a local address for packets to %s",
++			inet_ntoa(p->dest.sin_addr));
++		return -1;
++	}
++	if (new_addr.sin_addr.s_addr != p->source.sin_addr.s_addr) {
++		char addr1[16];
++		p->source.sin_addr = new_addr.sin_addr;
++		strcpy(addr1, inet_ntoa(p->dest.sin_addr));
++		syslog(LOG_NOTICE,
++			"local address for %s is %s", addr1, inet_ntoa(p->source.sin_addr));
++		return 1;
++	}
++	return 0;
+ }
+ 
+ /*
+@@ -404,44 +393,43 @@
+  */
+ struct peer_desc *peer_find(unsigned long spi, struct encap_method *encap)
+ {
+-    if (vpnpeer.local_sa->spi == spi
+-	&& vpnpeer.local_sa->em == encap)
+-	return &vpnpeer;
+-    syslog(LOG_ALERT, "unknown spi %ld", spi);
+-    return NULL;
++	if (vpnpeer.local_sa->spi == spi && vpnpeer.local_sa->em == encap)
++		return &vpnpeer;
++	syslog(LOG_ALERT, "unknown spi %ld", spi);
++	return NULL;
+ }
+ 
+ /*
+  * Compute HMAC for an arbitrary stream of bytes
+  */
+ int hmac_compute(int md_algo,
+-		 const unsigned char *data, unsigned int data_size,
+-		 unsigned char *digest, unsigned char do_store,
+-		 const unsigned char *secret, unsigned short secret_size)
++	const unsigned char *data, unsigned int data_size,
++	unsigned char *digest, unsigned char do_store,
++	const unsigned char *secret, unsigned short secret_size)
+ {
+-    gcry_md_hd_t md_ctx;
+-    int ret;
+-    unsigned char *hmac_digest;
+-    unsigned int hmac_len;
++	gcry_md_hd_t md_ctx;
++	int ret;
++	unsigned char *hmac_digest;
++	unsigned int hmac_len;
+ 
+-    /* See RFC 2104 */
+-    gcry_md_open(&md_ctx, md_algo, GCRY_MD_FLAG_HMAC);
+-    assert(md_ctx != 0);
+-    ret = gcry_md_setkey(md_ctx, secret, secret_size);
+-    assert(ret == 0);
+-    gcry_md_write(md_ctx, data, data_size);
+-    gcry_md_final(md_ctx);
+-    hmac_digest = gcry_md_read(md_ctx, 0);
+-    hmac_len = 12; /*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
++	/* See RFC 2104 */
++	gcry_md_open(&md_ctx, md_algo, GCRY_MD_FLAG_HMAC);
++	assert(md_ctx != 0);
++	ret = gcry_md_setkey(md_ctx, secret, secret_size);
++	assert(ret == 0);
++	gcry_md_write(md_ctx, data, data_size);
++	gcry_md_final(md_ctx);
++	hmac_digest = gcry_md_read(md_ctx, 0);
++	hmac_len = 12; /*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
+ 
+-    if (do_store) {
+-        memcpy(digest, hmac_digest, hmac_len);
+-        ret = 0;
+-    } else
+-        ret = memcmp(digest, hmac_digest, hmac_len);
+-    
+-    gcry_md_close(md_ctx);
+-    return ret;
++	if (do_store) {
++		memcpy(digest, hmac_digest, hmac_len);
++		ret = 0;
++	} else
++		ret = memcmp(digest, hmac_digest, hmac_len);
++
++	gcry_md_close(md_ctx);
++	return ret;
+ }
+ 
+ /*
+@@ -450,495 +438,460 @@
+  * to account for encapsulation data (not counted in "size").
+  */
+ void encap_esp_send_peer(struct encap_method *encap,
+-			 struct peer_desc *peer,
+-			 unsigned char *buf, unsigned int bufsize)
++	struct peer_desc *peer, unsigned char *buf, unsigned int bufsize)
+ {
+-    int sent;
+-    esp_encap_header_t *eh;
+-    struct ip *tip, *ip;
+-    unsigned char *iv, *cleartext;
+-    int i, padding, pad_blksz;
+-    unsigned int cleartextlen;
++	int sent;
++	esp_encap_header_t *eh;
++	struct ip *tip, *ip;
++	unsigned char *iv, *cleartext;
++	int i, padding, pad_blksz;
++	unsigned int cleartextlen;
+ 
+-    buf += MAX_HEADER;
++	buf += MAX_HEADER;
+ 
+-    /* Keep a pointer to the old IP header */
+-    tip = (struct ip *)buf;
++	/* Keep a pointer to the old IP header */
++	tip = (struct ip *)buf;
+ 
+-    encap->buf = buf;
+-    encap->buflen = bufsize;
++	encap->buf = buf;
++	encap->buflen = bufsize;
+ 
+-    /*
+-     * Add padding as necessary
+-     *
+-     * done: this should be checked, RFC 2406 section 2.4 is quite
+-     *	    obscure on that point.
+-     * seems fine
+-     */
+-    gcry_cipher_algo_info(peer->remote_sa->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &pad_blksz);
+-    while (pad_blksz & 3) /* must be multiple of 4 */
+-	    pad_blksz <<= 1;
+-    padding = pad_blksz - ((encap->buflen+2) % pad_blksz);
+-DEBUG(2, printf("sending packet: len = %d, padding = %d\n", encap->buflen, padding));
+-    if (padding == pad_blksz)
+-        padding = 0;
++	/*
++	 * Add padding as necessary
++	 *
++	 * done: this should be checked, RFC 2406 section 2.4 is quite
++	 *      obscure on that point.
++	 * seems fine
++	 */
++	gcry_cipher_algo_info(peer->remote_sa->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &pad_blksz);
++	while (pad_blksz & 3) /* must be multiple of 4 */
++		pad_blksz <<= 1;
++	padding = pad_blksz - ((encap->buflen + 2) % pad_blksz);
++	DEBUG(2, printf("sending packet: len = %d, padding = %d\n", encap->buflen, padding));
++	if (padding == pad_blksz)
++		padding = 0;
+ 
+-    for (i = 1; i <= padding; i++) {
+-        encap->buf[encap->buflen] = i;
+-	encap->buflen++;
+-    }
++	for (i = 1; i <= padding; i++) {
++		encap->buf[encap->buflen] = i;
++		encap->buflen++;
++	}
+ 
+-    /* Add trailing padlen and next_header */
+-    encap->buf[encap->buflen++] = padding;
+-    encap->buf[encap->buflen++] = IPPROTO_IPIP;
++	/* Add trailing padlen and next_header */
++	encap->buf[encap->buflen++] = padding;
++	encap->buf[encap->buflen++] = IPPROTO_IPIP;
+ 
+-    cleartext = buf;
+-    cleartextlen = encap->buflen;
++	cleartext = buf;
++	cleartextlen = encap->buflen;
+ 
+-    /* Prepend our encapsulation header and new IP header */
+-    encap->var_header_size = (encap->fixed_header_size + peer->remote_sa->ivlen);
++	/* Prepend our encapsulation header and new IP header */
++	encap->var_header_size = (encap->fixed_header_size + peer->remote_sa->ivlen);
+ 
+-    encap->buf -= sizeof(struct ip) + encap->var_header_size;
+-    encap->buflen += sizeof(struct ip) + encap->var_header_size;
++	encap->buf -= sizeof(struct ip) + encap->var_header_size;
++	encap->buflen += sizeof(struct ip) + encap->var_header_size;
+ 
+-    encap->bufpayload = sizeof(struct ip);
++	encap->bufpayload = sizeof(struct ip);
+ 
+-    eh = (esp_encap_header_t *)(encap->buf + encap->bufpayload);
+-    ip = (struct ip *)(encap->buf);
+-    eh->spi = htonl(peer->remote_sa->spi);
+-    eh->seq_id = htonl(++peer->remote_sa->seq_id);
++	eh = (esp_encap_header_t *) (encap->buf + encap->bufpayload);
++	ip = (struct ip *)(encap->buf);
++	eh->spi = htonl(peer->remote_sa->spi);
++	eh->seq_id = htonl(++peer->remote_sa->seq_id);
+ 
+-    /* Copy initialization vector in packet */
+-    iv = (unsigned char *)(eh + 1);
+-    gcry_randomize(iv, peer->remote_sa->ivlen, GCRY_WEAK_RANDOM);
+-hex_dump("iv", iv, peer->remote_sa->ivlen);
+-hex_dump("auth_secret", peer->remote_sa->auth_secret, peer->remote_sa->auth_secret_size);
++	/* Copy initialization vector in packet */
++	iv = (unsigned char *)(eh + 1);
++	gcry_randomize(iv, peer->remote_sa->ivlen, GCRY_WEAK_RANDOM);
++	hex_dump("iv", iv, peer->remote_sa->ivlen);
++	hex_dump("auth_secret", peer->remote_sa->auth_secret, peer->remote_sa->auth_secret_size);
+ 
+-    /* Fill non-mutable fields */
+-    ip->ip_v = IPVERSION;
+-    ip->ip_hl = 5;
+-    ip->ip_len = encap->buflen + (peer->remote_sa->md_algo? 12 :0);
++	/* Fill non-mutable fields */
++	ip->ip_v = IPVERSION;
++	ip->ip_hl = 5;
++	ip->ip_len = encap->buflen + (peer->remote_sa->md_algo ? 12 : 0);
+ #ifdef NEED_IPLEN_FIX
+-    ip->ip_len = htons(ip->ip_len);
++	ip->ip_len = htons(ip->ip_len);
+ #endif
+-                  /*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
+-    ip->ip_id = htons(ip_id++);
+-    ip->ip_p = IPPROTO_ESP;
+-    ip->ip_src = peer->remote_sa->source.sin_addr;
+-    ip->ip_dst = peer->remote_sa->dest.sin_addr;
++	/*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
++	ip->ip_id = htons(ip_id++);
++	ip->ip_p = IPPROTO_ESP;
++	ip->ip_src = peer->remote_sa->source.sin_addr;
++	ip->ip_dst = peer->remote_sa->dest.sin_addr;
+ 
+-    /* Fill mutable fields */
+-    ip->ip_tos = (bufsize < sizeof(struct ip)) ? 0 : tip->ip_tos;
+-    ip->ip_off = 0;
+-    ip->ip_ttl = IPDEFTTL;
+-    ip->ip_sum = 0;
++	/* Fill mutable fields */
++	ip->ip_tos = (bufsize < sizeof(struct ip)) ? 0 : tip->ip_tos;
++	ip->ip_off = 0;
++	ip->ip_ttl = IPDEFTTL;
++	ip->ip_sum = 0;
+ 
+ #if 1
+-    hex_dump("sending ESP packet (before crypt)", encap->buf, encap->buflen);
++	hex_dump("sending ESP packet (before crypt)", encap->buf, encap->buflen);
+ #endif
+-    
+-    {
+-      gcry_cipher_setiv(peer->remote_sa->cry_ctx, iv, peer->remote_sa->ivlen);
+-      gcry_cipher_encrypt(peer->remote_sa->cry_ctx, cleartext, cleartextlen, NULL, 0);
+-    }
++
++	{
++		gcry_cipher_setiv(peer->remote_sa->cry_ctx, iv, peer->remote_sa->ivlen);
++		gcry_cipher_encrypt(peer->remote_sa->cry_ctx, cleartext, cleartextlen, NULL, 0);
++	}
+ 
+ #if 1
+-    hex_dump("sending ESP packet (after crypt)", encap->buf, encap->buflen);
++	hex_dump("sending ESP packet (after crypt)", encap->buf, encap->buflen);
+ #endif
+ 
+-    /* Handle optional authentication field */
+-    if (peer->remote_sa->md_algo) {
+-	hmac_compute(peer->remote_sa->md_algo,
+-		     encap->buf+encap->bufpayload,
+-		     encap->var_header_size+cleartextlen,
+-		     encap->buf+encap->bufpayload
+-		     +encap->var_header_size+cleartextlen,
+-		     1,
+-		     peer->remote_sa->auth_secret,
+-		     peer->remote_sa->auth_secret_size);
+-	encap->buflen += 12; /*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
++	/* Handle optional authentication field */
++	if (peer->remote_sa->md_algo) {
++		hmac_compute(peer->remote_sa->md_algo,
++			encap->buf + encap->bufpayload,
++			encap->var_header_size + cleartextlen,
++			encap->buf + encap->bufpayload
++			+ encap->var_header_size + cleartextlen,
++			1, peer->remote_sa->auth_secret, peer->remote_sa->auth_secret_size);
++		encap->buflen += 12; /*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
+ #if 1
+-        hex_dump("sending ESP packet (after ah)", encap->buf, encap->buflen);
++		hex_dump("sending ESP packet (after ah)", encap->buf, encap->buflen);
+ #endif
+-    }
++	}
+ 
+-    ip->ip_sum = in_cksum((u_short *)encap->buf, sizeof(struct ip));
+-    
+-    sent = sendto(encap->fd, encap->buf, encap->buflen, 0,
+-		  (struct sockaddr *)&peer->remote_sa->dest,
+-		  sizeof(peer->remote_sa->dest));
+-    if (sent == -1) {
+-	syslog(LOG_ERR, "sendto: %m");
+-	return;
+-    }
+-    if (sent != encap->buflen)
+-	syslog(LOG_ALERT, "truncated out (%d out of %d)",
+-		sent, encap->buflen);
++	ip->ip_sum = in_cksum((u_short *) encap->buf, sizeof(struct ip));
++
++	sent = sendto(encap->fd, encap->buf, encap->buflen, 0,
++		(struct sockaddr *)&peer->remote_sa->dest, sizeof(peer->remote_sa->dest));
++	if (sent == -1) {
++		syslog(LOG_ERR, "sendto: %m");
++		return;
++	}
++	if (sent != encap->buflen)
++		syslog(LOG_ALERT, "truncated out (%d out of %d)", sent, encap->buflen);
+ }
+ 
+-int encap_esp_recv_peer(struct encap_method *encap,
+-			struct peer_desc *peer)
++int encap_esp_recv_peer(struct encap_method *encap, struct peer_desc *peer)
+ {
+-    int len, i, blksz;
+-    unsigned char padlen, next_header;
+-    unsigned char *pad;
+-    unsigned char *iv;
+-    struct esp_encap_header *eh;
+-
+-    eh = (struct esp_encap_header *)(encap->buf + encap->bufpayload);
+-    encap->var_header_size = peer->local_sa->ivlen;
+-    iv = encap->buf + encap->bufpayload + encap->fixed_header_size;
++	int len, i, blksz;
++	unsigned char padlen, next_header;
++	unsigned char *pad;
++	unsigned char *iv;
++	struct esp_encap_header *eh;
+ 
+-    len = encap->buflen - encap->bufpayload
+-        - encap->fixed_header_size - encap->var_header_size;
++	eh = (struct esp_encap_header *)(encap->buf + encap->bufpayload);
++	encap->var_header_size = peer->local_sa->ivlen;
++	iv = encap->buf + encap->bufpayload + encap->fixed_header_size;
+ 
+-    if (len < 0) {
+-        syslog(LOG_ALERT, "Packet too short");
+-        return -1;
+-    }
++	len = encap->buflen - encap->bufpayload - encap->fixed_header_size - encap->var_header_size;
+ 
+-    /* Handle optional authentication field */
+-    if (peer->local_sa->md_algo) {
+-	len -= 12; /*gcry_md_get_algo_dlen(peer->local_sa->md_algo);*/
+-	if (hmac_compute(peer->local_sa->md_algo,
+-			 encap->buf+encap->bufpayload,
+-			 encap->fixed_header_size+encap->var_header_size+len,
+-			 encap->buf+encap->bufpayload
+-			 +encap->fixed_header_size+encap->var_header_size+len,
+-			 0,
+-			 peer->local_sa->auth_secret,
+-			 peer->local_sa->auth_secret_size) != 0) {
+-	    syslog(LOG_ALERT, "HMAC mismatch in ESP mode");
+-	    return -1;
++	if (len < 0) {
++		syslog(LOG_ALERT, "Packet too short");
++		return -1;
+ 	}
+-    }
+ 
+-    gcry_cipher_algo_info(peer->local_sa->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &blksz);
+-    if ((len % blksz) != 0) {
+-        syslog(LOG_ALERT,
+-	       "payload len %d not a multiple of algorithm block size %d",
+-	       len, blksz);
+-	return -1;
+-    }
++	/* Handle optional authentication field */
++	if (peer->local_sa->md_algo) {
++		len -= 12; /*gcry_md_get_algo_dlen(peer->local_sa->md_algo); */
++		if (hmac_compute(peer->local_sa->md_algo,
++				encap->buf + encap->bufpayload,
++				encap->fixed_header_size + encap->var_header_size + len,
++				encap->buf + encap->bufpayload
++				+ encap->fixed_header_size + encap->var_header_size + len,
++				0,
++				peer->local_sa->auth_secret,
++				peer->local_sa->auth_secret_size) != 0) {
++			syslog(LOG_ALERT, "HMAC mismatch in ESP mode");
++			return -1;
++		}
++	}
+ 
++	gcry_cipher_algo_info(peer->local_sa->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &blksz);
++	if ((len % blksz) != 0) {
++		syslog(LOG_ALERT,
++			"payload len %d not a multiple of algorithm block size %d", len, blksz);
++		return -1;
++	}
+ #if 0
+-    printf("receiving ESP packet (before decrypt):\n");
+-    for (i = 0; i < len; i++)
+-        printf(" %02x", encap->buf[encap->bufpayload
+-				  +encap->fixed_header_size
+-				  +encap->var_header_size+i]);
+-    printf("\n");
++	printf("receiving ESP packet (before decrypt):\n");
++	for (i = 0; i < len; i++)
++		printf(" %02x", encap->buf[encap->bufpayload
++				+ encap->fixed_header_size + encap->var_header_size + i]);
++	printf("\n");
+ #endif
+-    
+-    {
+-      unsigned char *data;
+-      
+-      data = (encap->buf+encap->bufpayload
+-	      +encap->fixed_header_size
+-	      +encap->var_header_size);
+-      gcry_cipher_setiv(peer->local_sa->cry_ctx, iv, peer->local_sa->ivlen);
+-      gcry_cipher_decrypt(peer->local_sa->cry_ctx, data, len, NULL, 0);
+-    }
++
++	{
++		unsigned char *data;
++
++		data = (encap->buf + encap->bufpayload
++			+ encap->fixed_header_size + encap->var_header_size);
++		gcry_cipher_setiv(peer->local_sa->cry_ctx, iv, peer->local_sa->ivlen);
++		gcry_cipher_decrypt(peer->local_sa->cry_ctx, data, len, NULL, 0);
++	}
+ 
+ #if 0
+-    printf("receiving ESP packet (after decrypt %d):\n", len);
+-    for (i = 0; i < len; i++)
+-        printf(" %02x", encap->buf[encap->bufpayload
+-				  +encap->fixed_header_size
+-				  +encap->var_header_size+i]);
+-    printf("\n");
++	printf("receiving ESP packet (after decrypt %d):\n", len);
++	for (i = 0; i < len; i++)
++		printf(" %02x", encap->buf[encap->bufpayload
++				+ encap->fixed_header_size + encap->var_header_size + i]);
++	printf("\n");
+ #endif
+ 
+-    padlen = encap->buf[encap->bufpayload
+-		       +encap->fixed_header_size
+-		       +encap->var_header_size+len-2];
+-    next_header = encap->buf[encap->bufpayload
+-			    +encap->fixed_header_size
+-			    +encap->var_header_size+len-1];
+-
+-    if (padlen+2 > len) {
+-        syslog(LOG_ALERT, "Inconsistent padlen");
+-	return -1;
+-    }
+-    if (next_header != IPPROTO_IPIP) {
+-        syslog(LOG_ALERT, "Inconsistent next_header %d", next_header);
+-	return -1;
+-    }
++	padlen = encap->buf[encap->bufpayload
++		+ encap->fixed_header_size + encap->var_header_size + len - 2];
++	next_header = encap->buf[encap->bufpayload
++		+ encap->fixed_header_size + encap->var_header_size + len - 1];
+ 
++	if (padlen + 2 > len) {
++		syslog(LOG_ALERT, "Inconsistent padlen");
++		return -1;
++	}
++	if (next_header != IPPROTO_IPIP) {
++		syslog(LOG_ALERT, "Inconsistent next_header %d", next_header);
++		return -1;
++	}
+ #if 0
+-    printf("pad len: %d, next_header: %d\n", padlen, next_header);
++	printf("pad len: %d, next_header: %d\n", padlen, next_header);
+ #endif
+-    len -= padlen + 2;
++	len -= padlen + 2;
+ 
+-    /* Check padding */
+-    pad = encap->buf + encap->bufpayload
+-        + encap->fixed_header_size
+-        + encap->var_header_size + len;
+-    for (i = 1; i <= padlen; i++) {
+-        if (*pad != i) {
+-	    syslog(LOG_ALERT, "Bad padding");
+-	    return -1;
+-        }
+-	pad++;
+-    }
++	/* Check padding */
++	pad = encap->buf + encap->bufpayload
++		+ encap->fixed_header_size + encap->var_header_size + len;
++	for (i = 1; i <= padlen; i++) {
++		if (*pad != i) {
++			syslog(LOG_ALERT, "Bad padding");
++			return -1;
++		}
++		pad++;
++	}
+ 
+-    return 0;
++	return 0;
+ }
+ 
+-static void
+-vpnc_main_loop (struct peer_desc *peer,
+-		struct encap_method *meth,
+-		int tun_fd)
++static void vpnc_main_loop(struct peer_desc *peer, struct encap_method *meth, int tun_fd)
+ {
+-  struct pollfd pollfds[2];
+-  
+-  pollfds[0].fd = tun_fd;
+-  pollfds[0].events = POLLIN;
+-  pollfds[1].fd = encap_get_fd (meth);
+-  pollfds[1].events = POLLIN;
++	struct pollfd pollfds[2];
+ 
+-  for (;;)
+-    {
+-      int presult;
+-      
+-      do {
+-	presult = poll (pollfds, sizeof (pollfds) / sizeof (pollfds[0]), -1);
+-      } while (presult == -1 && errno == EINTR);
+-      if (presult == -1)
+-	{
+-	  syslog(LOG_ERR, "poll: %m");
+-	  continue;
+-	}
++	pollfds[0].fd = tun_fd;
++	pollfds[0].events = POLLIN;
++	pollfds[1].fd = encap_get_fd(meth);
++	pollfds[1].events = POLLIN;
+ 
+-      if (pollfds[0].revents & POLLIN)
+-	{
+-	  int pack;
+-	  
+-	  /* Receive a packet from the tunnel interface */
+-	  pack = tun_read(peer->tun_fd,
+-		      buf+MAX_HEADER,
+-		      MAX_PACKET);
+-	  if (pack == -1) {
+-	    syslog(LOG_ERR, "read: %m");
+-	    continue;
+-	  }
+-	  
+-	  if (peer->remote_sa->use_dest == 0) {
+-	    syslog(LOG_NOTICE,
+-		   "peer hasn't a known address yet");
+-	    continue;
+-	  }
+-	  
+-	  if (((struct ip *)(buf+MAX_HEADER))->ip_dst.s_addr
+-	      == peer->remote_sa->dest.sin_addr.s_addr) {
+-	    syslog(LOG_ALERT, "routing loop to %s",
+-		   inet_ntoa(peer->remote_sa->dest.sin_addr));
+-	    continue;
+-	  }
+-	  
+-	  /* Encapsulate and send to the other end of the tunnel */
+-	  encap_send_peer(peer->remote_sa->em, peer, buf, pack);
+-	  
+-	  /* Update sent packet timeout */
+-	  peer->remote_sa->last_packet_sent = time (NULL);
+-	}
+-      if (pollfds[1].revents & POLLIN)
+-	{
+-	  /* Receive a packet from a socket */
+-	  struct peer_desc *peer;
+-	  int pack;
+-	  struct sockaddr_in from;
+-	  
+-	  pack = encap_recv(meth, buf, MAX_HEADER+MAX_PACKET, &from);
+-	  if (pack == -1)
+-	    continue;
+-	  
+-	  peer = encap_peer_find(meth);
+-	  if (peer == NULL) {
+-	    syslog(LOG_NOTICE, "unknown spi from %s",
+-		   inet_ntoa(from.sin_addr));
+-	    continue;
+-	  }
+-	  
+-	  /* Check auth digest and/or decrypt */
+-	  if (encap_recv_peer(meth, peer) != 0)
+-	    continue;
+-	  
+-	  /* Check origin IP; update our copy if need be */
+-	  if (peer->remote_sa->use_dest == 0
+-	      || from.sin_addr.s_addr
+-	      != peer->remote_sa->dest.sin_addr.s_addr) {
+-	    /* remote end changed address */
+-	    char addr1[16];
+-	    strcpy(addr1, inet_ntoa(peer->remote_sa->dest.sin_addr));
+-	    syslog(LOG_NOTICE,
+-		   "spi %ld: remote address changed from %s to %s",
+-		   peer->remote_sa->spi,
+-		   addr1,
+-		   inet_ntoa(from.sin_addr));
+-	    peer->remote_sa->dest.sin_addr.s_addr
+-	      = from.sin_addr.s_addr;
+-	    peer->remote_sa->use_dest = 1;
+-	    update_sa_addr(peer->remote_sa);
+-	  }
+-	  /* Update received packet timeout */
+-	  peer->remote_sa->last_packet_recv = time (NULL);
+-	  
+-	  if (encap_any_decap(meth) == 0)
+-	    syslog(LOG_DEBUG, "received update probe from peer");
+-	  else
+-	    /* Send the decapsulated packet to the tunnel interface */
+-	    tun_send_ip(meth, peer->tun_fd);
++	for (;;) {
++		int presult;
++
++		do {
++			presult = poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), -1);
++		} while (presult == -1 && errno == EINTR);
++		if (presult == -1) {
++			syslog(LOG_ERR, "poll: %m");
++			continue;
++		}
++
++		if (pollfds[0].revents & POLLIN) {
++			int pack;
++
++			/* Receive a packet from the tunnel interface */
++			pack = tun_read(peer->tun_fd, buf + MAX_HEADER, MAX_PACKET);
++			if (pack == -1) {
++				syslog(LOG_ERR, "read: %m");
++				continue;
++			}
++
++			if (peer->remote_sa->use_dest == 0) {
++				syslog(LOG_NOTICE, "peer hasn't a known address yet");
++				continue;
++			}
++
++			if (((struct ip *)(buf + MAX_HEADER))->ip_dst.s_addr
++				== peer->remote_sa->dest.sin_addr.s_addr) {
++				syslog(LOG_ALERT, "routing loop to %s",
++					inet_ntoa(peer->remote_sa->dest.sin_addr));
++				continue;
++			}
++
++			/* Encapsulate and send to the other end of the tunnel */
++			encap_send_peer(peer->remote_sa->em, peer, buf, pack);
++
++			/* Update sent packet timeout */
++			peer->remote_sa->last_packet_sent = time(NULL);
++		}
++		if (pollfds[1].revents & POLLIN) {
++			/* Receive a packet from a socket */
++			struct peer_desc *peer;
++			int pack;
++			struct sockaddr_in from;
++
++			pack = encap_recv(meth, buf, MAX_HEADER + MAX_PACKET, &from);
++			if (pack == -1)
++				continue;
++
++			peer = encap_peer_find(meth);
++			if (peer == NULL) {
++				syslog(LOG_NOTICE, "unknown spi from %s", inet_ntoa(from.sin_addr));
++				continue;
++			}
++
++			/* Check auth digest and/or decrypt */
++			if (encap_recv_peer(meth, peer) != 0)
++				continue;
++
++			/* Check origin IP; update our copy if need be */
++			if (peer->remote_sa->use_dest == 0
++				|| from.sin_addr.s_addr != peer->remote_sa->dest.sin_addr.s_addr) {
++				/* remote end changed address */
++				char addr1[16];
++				strcpy(addr1, inet_ntoa(peer->remote_sa->dest.sin_addr));
++				syslog(LOG_NOTICE,
++					"spi %ld: remote address changed from %s to %s",
++					peer->remote_sa->spi, addr1, inet_ntoa(from.sin_addr));
++				peer->remote_sa->dest.sin_addr.s_addr = from.sin_addr.s_addr;
++				peer->remote_sa->use_dest = 1;
++				update_sa_addr(peer->remote_sa);
++			}
++			/* Update received packet timeout */
++			peer->remote_sa->last_packet_recv = time(NULL);
++
++			if (encap_any_decap(meth) == 0)
++				syslog(LOG_DEBUG, "received update probe from peer");
++			else
++				/* Send the decapsulated packet to the tunnel interface */
++				tun_send_ip(meth, peer->tun_fd);
++		}
+ 	}
+-    }
+ }
+ 
+ static uint8_t *volatile kill_packet;
+ static size_t volatile kill_packet_size;
+-static struct sockaddr * volatile kill_dest;
++static struct sockaddr *volatile kill_dest;
+ 
+-void
+-killit(int signum)
++void killit(int signum)
+ {
+-  int sock = signum; /* unused */
+-  sock = socket (AF_INET, SOCK_DGRAM, 0);
+-  if (sock >= 0)
+-    {
+-      sendto (sock, kill_packet, kill_packet_size, 0,
+-	      kill_dest, sizeof (struct sockaddr_in));
+-      close (sock);
+-    }
+-  tun_close(tun_fd, tun_name);
+-  syslog(LOG_NOTICE, "terminated");
+-  _exit (0);
++	int sock = signum; /* unused */
++	sock = socket(AF_INET, SOCK_DGRAM, 0);
++	if (sock >= 0) {
++		sendto(sock, kill_packet, kill_packet_size, 0,
++			kill_dest, sizeof(struct sockaddr_in));
++		close(sock);
++	}
++	tun_close(oursa->tun_fd, oursa->tun_name);
++	syslog(LOG_NOTICE, "terminated");
++	_exit(0);
+ }
+ 
+-void
+-write_pidfile(const char *pidfile)
++void write_pidfile(const char *pidfile)
+ {
+ 	FILE *pf;
+-	
++
+ 	if (pidfile == NULL)
+ 		return;
+-	
++
+ 	pf = fopen(pidfile, "w");
+ 	if (pf == NULL) {
+ 		syslog(LOG_WARNING, "can't open pidfile %s for writing", pidfile);
+ 		return;
+ 	}
+-	
++
+ 	fprintf(pf, "%d\n", (int)getpid());
+ 	fclose(pf);
+ }
+ 
+ void
+ vpnc_doit(unsigned long tous_spi,
+-	  const unsigned char *tous_key, 
+-	  struct sockaddr_in *tous_dest,
+-	  unsigned long tothem_spi,
+-	  const unsigned char *tothem_key,
+-	  struct sockaddr_in *tothem_dest,
+-	  int tun_fd, int md_algo, int cry_algo,
+-	  uint8_t *kill_packet_p, size_t kill_packet_size_p,
+-	  struct sockaddr *kill_dest_p,
+-	  const char *pidfile)
++	const unsigned char *tous_key,
++	struct sockaddr_in *tous_dest,
++	unsigned long tothem_spi,
++	const unsigned char *tothem_key,
++	struct sockaddr_in *tothem_dest,
++	int tun_fd, int md_algo, int cry_algo,
++	uint8_t * kill_packet_p, size_t kill_packet_size_p,
++	struct sockaddr *kill_dest_p, const char *pidfile)
+ {
+-  struct encap_method meth;
++	struct encap_method meth;
+ 
+-  static struct sa_desc tous_sa, tothem_sa;
+-  time_t t = time(NULL);
++	static struct sa_desc tous_sa, tothem_sa;
++	time_t t = time(NULL);
+ 
+-  if (encap_esp_new(&meth, IPPROTO_ESP) == -1)
+-    exit(1);
++	if (encap_esp_new(&meth, IPPROTO_ESP) == -1)
++		exit(1);
+ 
+-  tous_sa.next = remote_sa_list;
+-  remote_sa_list = &tous_sa;
+-  tous_sa.em = &meth;
+-  tous_sa.last_packet_recv = t;
+-  tous_sa.last_packet_sent = t;
+-  tous_sa.last_checkifaddr = t;
+-  tous_sa.md_algo = md_algo;
+-  tous_sa.spi = htonl (tous_spi);
+-  tous_sa.enc_secret = tous_key;
+-  gcry_cipher_algo_info(cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(tous_sa.enc_secret_size));
+-hex_dump("tous.enc_secret", tous_sa.enc_secret, tous_sa.enc_secret_size);
+-  tous_sa.auth_secret = tous_key + tous_sa.enc_secret_size;
+-  tous_sa.auth_secret_size = gcry_md_get_algo_dlen(md_algo);
+-hex_dump("tous.auth_secret", tous_sa.auth_secret, tous_sa.auth_secret_size);
+-  memcpy (&tous_sa.init, tous_dest, sizeof (struct sockaddr_in));
+-  memcpy (&tous_sa.dest, tous_dest, sizeof (struct sockaddr_in));
+-  if (update_sa_addr(&tous_sa) != -1)
+-    {
+-      tous_sa.use_fallback = 1;
+-      tous_sa.use_dest = 1;
+-    }
+-  tous_sa.cry_algo = cry_algo;
+-  gcry_cipher_open(&tous_sa.cry_ctx, tous_sa.cry_algo, GCRY_CIPHER_MODE_CBC, 0);
+-  gcry_cipher_setkey(tous_sa.cry_ctx, tous_sa.enc_secret, tous_sa.enc_secret_size);
+-  gcry_cipher_algo_info(tous_sa.cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(tous_sa.ivlen));
+-  
+-  tothem_sa.next = local_sa_list;
+-  local_sa_list = &tothem_sa;
+-  tothem_sa.em = &meth;
+-  tothem_sa.last_packet_recv = t;
+-  tothem_sa.last_packet_sent = t;
+-  tothem_sa.last_checkifaddr = t;
+-  tothem_sa.md_algo = md_algo;
+-  tothem_sa.spi = htonl (tothem_spi);
+-  tothem_sa.enc_secret = tothem_key;
+-  gcry_cipher_algo_info(cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(tothem_sa.enc_secret_size));
+-hex_dump("tothem.enc_secret", tothem_sa.enc_secret, tothem_sa.enc_secret_size);
+-  tothem_sa.auth_secret = tothem_key + tothem_sa.enc_secret_size;
+-  tothem_sa.auth_secret_size = gcry_md_get_algo_dlen(md_algo);
+-hex_dump("tothem.auth_secret", tothem_sa.auth_secret, tothem_sa.auth_secret_size);
+-  memcpy (&tothem_sa.init, tothem_dest, sizeof (struct sockaddr_in));
+-  memcpy (&tothem_sa.dest, tothem_dest, sizeof (struct sockaddr_in));
+-  if (update_sa_addr(&tothem_sa) != -1)
+-    {
+-      tothem_sa.use_fallback = 1;
+-      tothem_sa.use_dest = 1;
+-    }
+-  tothem_sa.cry_algo = cry_algo;
+-  gcry_cipher_open(&tothem_sa.cry_ctx, tothem_sa.cry_algo, GCRY_CIPHER_MODE_CBC, 0);
+-  gcry_cipher_setkey(tothem_sa.cry_ctx, tothem_sa.enc_secret, tothem_sa.enc_secret_size);
+-  gcry_cipher_algo_info(tothem_sa.cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(tothem_sa.ivlen));
+-  
+-  vpnpeer.tun_fd = tun_fd;
+-  vpnpeer.local_sa = &tous_sa;
+-  vpnpeer.remote_sa = &tothem_sa;
++	tous_sa.next = remote_sa_list;
++	remote_sa_list = &tous_sa;
++	tous_sa.em = &meth;
++	tous_sa.last_packet_recv = t;
++	tous_sa.last_packet_sent = t;
++	tous_sa.last_checkifaddr = t;
++	tous_sa.md_algo = md_algo;
++	tous_sa.spi = htonl(tous_spi);
++	tous_sa.enc_secret = tous_key;
++	gcry_cipher_algo_info(cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(tous_sa.enc_secret_size));
++	hex_dump("tous.enc_secret", tous_sa.enc_secret, tous_sa.enc_secret_size);
++	tous_sa.auth_secret = tous_key + tous_sa.enc_secret_size;
++	tous_sa.auth_secret_size = gcry_md_get_algo_dlen(md_algo);
++	hex_dump("tous.auth_secret", tous_sa.auth_secret, tous_sa.auth_secret_size);
++	memcpy(&tous_sa.init, tous_dest, sizeof(struct sockaddr_in));
++	memcpy(&tous_sa.dest, tous_dest, sizeof(struct sockaddr_in));
++	if (update_sa_addr(&tous_sa) != -1) {
++		tous_sa.use_fallback = 1;
++		tous_sa.use_dest = 1;
++	}
++	tous_sa.cry_algo = cry_algo;
++	gcry_cipher_open(&tous_sa.cry_ctx, tous_sa.cry_algo, GCRY_CIPHER_MODE_CBC, 0);
++	gcry_cipher_setkey(tous_sa.cry_ctx, tous_sa.enc_secret, tous_sa.enc_secret_size);
++	gcry_cipher_algo_info(tous_sa.cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(tous_sa.ivlen));
+ 
+-  openlog ("vpnc", LOG_PID, LOG_DAEMON);
+-    {
+-      kill_packet = kill_packet_p;
+-      kill_packet_size = kill_packet_size_p;
+-      kill_dest = kill_dest_p;
+-      
+-      signal (SIGHUP, killit);
+-      signal (SIGINT, killit);
+-      signal (SIGTERM, killit);
+-      signal (SIGXCPU, killit);
++	tothem_sa.next = local_sa_list;
++	local_sa_list = &tothem_sa;
++	tothem_sa.em = &meth;
++	tothem_sa.last_packet_recv = t;
++	tothem_sa.last_packet_sent = t;
++	tothem_sa.last_checkifaddr = t;
++	tothem_sa.md_algo = md_algo;
++	tothem_sa.spi = htonl(tothem_spi);
++	tothem_sa.enc_secret = tothem_key;
++	gcry_cipher_algo_info(cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(tothem_sa.enc_secret_size));
++	hex_dump("tothem.enc_secret", tothem_sa.enc_secret, tothem_sa.enc_secret_size);
++	tothem_sa.auth_secret = tothem_key + tothem_sa.enc_secret_size;
++	tothem_sa.auth_secret_size = gcry_md_get_algo_dlen(md_algo);
++	hex_dump("tothem.auth_secret", tothem_sa.auth_secret, tothem_sa.auth_secret_size);
++	memcpy(&tothem_sa.init, tothem_dest, sizeof(struct sockaddr_in));
++	memcpy(&tothem_sa.dest, tothem_dest, sizeof(struct sockaddr_in));
++	if (update_sa_addr(&tothem_sa) != -1) {
++		tothem_sa.use_fallback = 1;
++		tothem_sa.use_dest = 1;
++	}
++	tothem_sa.cry_algo = cry_algo;
++	gcry_cipher_open(&tothem_sa.cry_ctx, tothem_sa.cry_algo, GCRY_CIPHER_MODE_CBC, 0);
++	gcry_cipher_setkey(tothem_sa.cry_ctx, tothem_sa.enc_secret, tothem_sa.enc_secret_size);
++	gcry_cipher_algo_info(tothem_sa.cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(tothem_sa.ivlen));
++
++	vpnpeer.tun_fd = tun_fd;
++	vpnpeer.local_sa = &tous_sa;
++	vpnpeer.remote_sa = &tothem_sa;
++
++	kill_packet = kill_packet_p;
++	kill_packet_size = kill_packet_size_p;
++	kill_dest = kill_dest_p;
++
++	signal(SIGHUP, killit);
++	signal(SIGINT, killit);
++	signal(SIGTERM, killit);
++	signal(SIGXCPU, killit);
+ #if defined(SIGPWR)
+-      signal (SIGPWR, killit);
++	signal(SIGPWR, killit);
+ #endif
+ 
+-      chdir ("/");
+-      
+-      setsid ();
+-      if (!opt_nd) {
+-         pid_t pid;
+-         if((pid=fork()) < 0) {
+-            fprintf(stderr, "Warning, could not fork the child process!\n");
+-         } else if (pid==0) {
+-            close (0); close (1); close (2);
+-	    write_pidfile(pidfile);
+-            vpnc_main_loop (&vpnpeer, &meth, tun_fd); /* never returns */
+-            exit(0);
+-         } else {
+-            printf("VPNC started in background (pid: %d)...\n", (int)pid);
+-            exit(0);
+-         }
+-      }
+-      printf("VPNC started in foreground...\n");
+-      vpnc_main_loop (&vpnpeer, &meth, tun_fd);
+-  }
++	chdir("/");
++
++	setsid();
++	if (!opt_nd) {
++		pid_t pid;
++		if ((pid = fork()) < 0) {
++			fprintf(stderr, "Warning, could not fork the child process!\n");
++		} else if (pid == 0) {
++			close(0);
++			close(1);
++			close(2);
++			openlog("vpnc", LOG_PID, LOG_DAEMON);
++			write_pidfile(pidfile);
++		} else {
++			printf("VPNC started in background (pid: %d)...\n", (int)pid);
++			exit(0);
++		}
++	} else {
++		printf("VPNC started in foreground...\n");
++		openlog("vpnc", LOG_PID, LOG_DAEMON);
++	}
++
++	vpnc_main_loop(&vpnpeer, &meth, tun_fd); /* never returns */
++	exit(0);
+ }
+diff -Nurd vpnc-0.2-rm+zomb.1/VERSION new/VERSION
+--- vpnc-0.2-rm+zomb.1/VERSION	2004-05-13 23:21:11.000000000 +0200
++++ new/VERSION	2004-05-23 02:27:19.000000000 +0200
+@@ -1 +1 @@
+-0.2-rm+zomb.1
++0.2-rm+zomb.1+2pre1-2004-06-17
+diff -Nurd vpnc-0.2-rm+zomb.1/vpnc.8 new/vpnc.8
+--- vpnc-0.2-rm+zomb.1/vpnc.8	2004-05-13 23:33:56.000000000 +0200
++++ new/vpnc.8	2004-05-30 19:30:05.000000000 +0200
+@@ -208,16 +208,16 @@
+ See also the
+ .B \-\-print\-config
+ option to generate a config file, and the example file in the package
+-documentation directory where more advanced usage is described.
++documentation directory where more advanced usage is demonstrated.
+ 
+ Advanced features like manual setting of multiple target routes is
+ documented in the example files of the vpnc package.
+ 
+ .SH TODO
+ .PD 0
+-Re-keying is no implemented yet (default rekey-intervall is 8 hours).
++Re-keying is not implemented yet (default rekey-intervall is 8 hours).
+ .P
+-certificate support (Pre-Shared-Key + XAUTH is known to be insecure).
++Certificate support (Pre-Shared-Key + XAUTH is known to be insecure).
+ .P
+ IPSec over UDP
+ .PD
+diff -Nurd vpnc-0.2-rm+zomb.1/vpnc.c new/vpnc.c
+--- vpnc-0.2-rm+zomb.1/vpnc.c	2004-05-13 19:24:34.000000000 +0200
++++ new/vpnc.c	2004-06-10 11:19:53.000000000 +0200
+@@ -36,50 +36,32 @@
+ 
+ #include <gcrypt.h>
+ 
+-#include "isakmp-pkt.h"
+ #include "sysdep.h"
++#include "config.h"
++#include "isakmp-pkt.h"
+ #include "math_group.h"
+ #include "dh.h"
+ #include "vpnc.h"
+ 
+-extern void vpnc_doit(unsigned long tous_spi,
+-		      const unsigned char *tous_key, 
+-		      struct sockaddr_in *tous_dest,
+-		      unsigned long tothem_spi,
+-		      const unsigned char *tothem_key,
+-		      struct sockaddr_in *tothem_dest,
+-		      int tun_fd, int md_algo, int cry_algo,
+-		      uint8_t *kill_packet_p, size_t kill_packet_size_p,
+-		      struct sockaddr *kill_dest_p,
+-		      const char *pidfile);
++struct sa_block oursa[1];
+ 
+-enum config_enum {
+-  CONFIG_NONE,
+-  CONFIG_CONFIG_SCRIPT,
+-  CONFIG_DEBUG,
+-  CONFIG_DOMAIN,
+-  CONFIG_ENABLE_1DES,
+-  CONFIG_ND,
+-  CONFIG_NON_INTERACTIVE,
+-  CONFIG_PID_FILE,
+-  CONFIG_LOCAL_PORT,
+-  CONFIG_VERSION,
+-  CONFIG_IF_NAME,
+-  CONFIG_IKE_DH,
+-  CONFIG_IPSEC_PFS,
+-  CONFIG_IPSEC_GATEWAY,
+-  CONFIG_IPSEC_ID,
+-  CONFIG_IPSEC_SECRET,
+-  CONFIG_XAUTH_USERNAME,
+-  CONFIG_XAUTH_PASSWORD,
+-  LAST_CONFIG
+-};
++static int sockfd = -1;
++static struct sockaddr *dest_addr;
++static int timeout = 5000; /* 5 seconds */
++static uint8_t *resend_hash = NULL;
+ 
+-static const char *config[LAST_CONFIG];
++static uint8_t r_packet[2048];
++static ssize_t r_length;
+ 
+-int opt_debug = 0;
+-int opt_nd;
+-int opt_1des;
++extern void vpnc_doit(unsigned long tous_spi,
++	const unsigned char *tous_key,
++	struct sockaddr_in *tous_dest,
++	unsigned long tothem_spi,
++	const unsigned char *tothem_key,
++	struct sockaddr_in *tothem_dest,
++	int tun_fd, int md_algo, int cry_algo,
++	uint8_t * kill_packet_p, size_t kill_packet_size_p,
++	struct sockaddr *kill_dest_p, const char *pidfile);
+ 
+ enum supp_algo_key {
+ 	SUPP_ALGO_NAME,
+@@ -94,80 +76,73 @@
+ 	SUPP_ALGO_CRYPT
+ };
+ 
+-typedef struct {
+-	const char *name;
+-	int my_id, ike_sa_id, ipsec_sa_id;
+-	int keylen;
+-} supported_algo_t;
+-
+ supported_algo_t supp_dh_group[] = {
+-	{ "nopfs", 0, 0, 0, 0 },
+-	{ "dh1", OAKLEY_GRP_1, IKE_GROUP_MODP_768, IKE_GROUP_MODP_768, 0 },
+-	{ "dh2", OAKLEY_GRP_2, IKE_GROUP_MODP_1024, IKE_GROUP_MODP_1024, 0 },
+-	{ "dh5", OAKLEY_GRP_5, IKE_GROUP_MODP_1536, IKE_GROUP_MODP_1536, 0 },
++	{"nopfs", 0, 0, 0, 0},
++	{"dh1", OAKLEY_GRP_1, IKE_GROUP_MODP_768, IKE_GROUP_MODP_768, 0},
++	{"dh2", OAKLEY_GRP_2, IKE_GROUP_MODP_1024, IKE_GROUP_MODP_1024, 0},
++	{"dh5", OAKLEY_GRP_5, IKE_GROUP_MODP_1536, IKE_GROUP_MODP_1536, 0},
+ 	/*{ "dh7", OAKLEY_GRP_7, IKE_GROUP_EC2N_163K, IKE_GROUP_EC2N_163K, 0 } note: code missing */
++	{NULL, 0, 0, 0, 0}
+ };
+ 
+ supported_algo_t supp_hash[] = {
+-	{ "md5", GCRY_MD_MD5, IKE_HASH_MD5, IPSEC_AUTH_HMAC_MD5, 0 },
+-	{ "sha1", GCRY_MD_SHA1, IKE_HASH_SHA, IPSEC_AUTH_HMAC_SHA, 0 }
++	{"md5", GCRY_MD_MD5, IKE_HASH_MD5, IPSEC_AUTH_HMAC_MD5, 0},
++	{"sha1", GCRY_MD_SHA1, IKE_HASH_SHA, IPSEC_AUTH_HMAC_SHA, 0},
++	{NULL, 0, 0, 0, 0}
+ };
+ 
+ supported_algo_t supp_crypt[] = {
+-	{ "des", GCRY_CIPHER_DES, IKE_ENC_DES_CBC, ISAKMP_IPSEC_ESP_DES, 0 }, /*note: working, but not recommended */
+-	{ "3des", GCRY_CIPHER_3DES, IKE_ENC_3DES_CBC, ISAKMP_IPSEC_ESP_3DES, 0 },
+-	{ "aes128", GCRY_CIPHER_AES128, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 128 },
+-	{ "aes192", GCRY_CIPHER_AES192, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 192 },
+-	{ "aes256", GCRY_CIPHER_AES256, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 256 },
++	/*note: working, but not recommended */
++	{"des", GCRY_CIPHER_DES, IKE_ENC_DES_CBC, ISAKMP_IPSEC_ESP_DES, 0},
++	{"3des", GCRY_CIPHER_3DES, IKE_ENC_3DES_CBC, ISAKMP_IPSEC_ESP_3DES, 0},
++	{"aes128", GCRY_CIPHER_AES128, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 128},
++	{"aes192", GCRY_CIPHER_AES192, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 192},
++	{"aes256", GCRY_CIPHER_AES256, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 256},
++	{NULL, 0, 0, 0, 0}
+ };
+ 
+-const supported_algo_t *
+-get_algo(enum algo_group what, enum supp_algo_key key, int id, const char *name, int keylen)
++const supported_algo_t *get_algo(enum algo_group what, enum supp_algo_key key, int id,
++	const char *name, int keylen)
+ {
+ 	supported_algo_t *sa = NULL;
+-	int i = 0, cnt = 0, val = 0;
++	int i = 0, val = 0;
+ 	const char *valname = NULL;
+-	
++
+ 	assert(what <= SUPP_ALGO_CRYPT);
+ 	assert(key <= SUPP_ALGO_IPSEC_SA);
+-	
++
+ 	switch (what) {
+-		case SUPP_ALGO_DH_GROUP:
+-			sa = supp_dh_group;
+-			cnt = sizeof(supp_dh_group) / sizeof(supp_dh_group[0]);
++	case SUPP_ALGO_DH_GROUP:
++		sa = supp_dh_group;
++		break;
++	case SUPP_ALGO_HASH:
++		sa = supp_hash;
++		break;
++	case SUPP_ALGO_CRYPT:
++		sa = supp_crypt;
++		break;
++	}
++
++	for (i = 0; sa[i].name != NULL; i++) {
++		switch (key) {
++		case SUPP_ALGO_NAME:
++			valname = sa[i].name;
+ 			break;
+-		case SUPP_ALGO_HASH:
+-			sa = supp_hash;
+-			cnt = sizeof(supp_hash) / sizeof(supp_hash[0]);
++		case SUPP_ALGO_MY_ID:
++			val = sa[i].my_id;
+ 			break;
+-		case SUPP_ALGO_CRYPT:
+-			sa = supp_crypt;
+-			cnt = sizeof(supp_crypt) / sizeof(supp_crypt[0]);
++		case SUPP_ALGO_IKE_SA:
++			val = sa[i].ike_sa_id;
++			break;
++		case SUPP_ALGO_IPSEC_SA:
++			val = sa[i].ipsec_sa_id;
+ 			break;
+-	}
+-	
+-	for (i = 0; i < cnt; i++) {
+-		switch (key) {
+-			case SUPP_ALGO_NAME:
+-				valname = sa[i].name;
+-				break;
+-			case SUPP_ALGO_MY_ID:
+-				val = sa[i].my_id;
+-				break;
+-			case SUPP_ALGO_IKE_SA:
+-				val = sa[i].ike_sa_id;
+-				break;
+-			case SUPP_ALGO_IPSEC_SA:
+-				val = sa[i].ipsec_sa_id;
+-				break;
+ 		}
+-		if ((key == SUPP_ALGO_NAME) ?
+-			!strcasecmp(name, valname) :
+-			(val == id))
++		if ((key == SUPP_ALGO_NAME) ? !strcasecmp(name, valname) : (val == id))
+ 			if (keylen == sa[i].keylen)
+ 				return sa + i;
+ 	}
+-	
++
+ 	return NULL;
+ }
+ 
+@@ -178,155 +153,150 @@
+ const supported_algo_t *get_dh_group_ipsec(int server_setting)
+ {
+ 	const char *pfs_setting = config[CONFIG_IPSEC_PFS];
+-	
++
+ 	if (!strcmp(config[CONFIG_IPSEC_PFS], "server")) {
+ 		/* treat server_setting == -1 (unknown) as 0 */
+ 		pfs_setting = (server_setting == 1) ? "dh2" : "nopfs";
+ 	}
+-	
++
+ 	return get_algo(SUPP_ALGO_DH_GROUP, SUPP_ALGO_NAME, 0, pfs_setting, 0);
+ }
+ 
+-/* * */
+-
+ static __inline__ int min(int a, int b)
+ {
+ 	return (a < b) ? a : b;
+ }
+ 
+-void hex_dump (const char *str, const void *data, size_t len)
++static void addenv(const void *name, const char *value)
+ {
+-	size_t i;
+-	const uint8_t *p = data;
+-	
+-  if(opt_debug >= 3) {
+-       	printf("%s:%c", str, (len <= 32)? ' ':'\n');
+-       	for (i = 0; i < len; i++) {
+-       		if (i && !(i%32))
+-       			printf("\n");
+-       		else if (i && !(i%4))
+-       			printf(" ");
+-       		printf("%02x", p[i]);
+-       	}
+-       	printf("\n");
+-  }
++	char *strbuf = NULL, *oldval;
++
++	oldval = getenv(name);
++	if (oldval != NULL) {
++		strbuf = xallocc(strlen(oldval) + 1 + strlen(value) + 1);
++		strcat(strbuf, oldval);
++		strcat(strbuf, " ");
++		strcat(strbuf, value);
++	}
++
++	setenv(name, strbuf ? strbuf : value, 1);
++
++	if (strbuf)
++		free(strbuf);
+ }
+ 
+-static int
+-make_socket (uint16_t port)
++static void addenv_ipv4(const void *name, uint8_t * data)
+ {
+-  int sock;
+-  struct sockaddr_in name;
++	addenv(name, inet_ntoa(*((struct in_addr *)data)));
++}
+ 
+-  /* Create the socket. */
+-  sock = socket (PF_INET, SOCK_DGRAM, 0);
+-  if (sock < 0)
+-    error (1, errno, "making socket");
++static int make_socket(uint16_t port)
++{
++	int sock;
++	struct sockaddr_in name;
+ 
+-  /* Give the socket a name. */
+-  name.sin_family = AF_INET;
+-  name.sin_port = htons (port);
+-  name.sin_addr.s_addr = htonl (INADDR_ANY);
+-  if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
+-    error (1, errno, "binding to port %d", port);
++	/* Create the socket. */
++	sock = socket(PF_INET, SOCK_DGRAM, 0);
++	if (sock < 0)
++		error(1, errno, "making socket");
+ 
+-  return sock;
++	/* Give the socket a name. */
++	name.sin_family = AF_INET;
++	name.sin_port = htons(port);
++	name.sin_addr.s_addr = htonl(INADDR_ANY);
++	if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0)
++		error(1, errno, "binding to port %d", port);
++
++	return sock;
+ }
+ 
+-static struct sockaddr *
+-init_sockaddr (const char *hostname,
+-	       uint16_t port)
++static struct sockaddr *init_sockaddr(const char *hostname, uint16_t port)
+ {
+-  struct hostent *hostinfo;
+-  struct sockaddr_in *result;
+-  
+-  result = malloc (sizeof (struct sockaddr_in));
+-  if (result == NULL)
+-    error (1, errno, "out of memory");
++	struct hostent *hostinfo;
++	struct sockaddr_in *result;
+ 
+-  result->sin_family = AF_INET;
+-  result->sin_port = htons (port);
+-  if (inet_aton (hostname, &result->sin_addr) == 0)
+-    {
+-      hostinfo = gethostbyname (hostname);
+-      if (hostinfo == NULL)
+-	error (1, 0, "unknown host `%s'\n", hostname);
+-      result->sin_addr = *(struct in_addr *) hostinfo->h_addr;
+-    }
+-  return (struct sockaddr *)result;
+-}
++	result = malloc(sizeof(struct sockaddr_in));
++	if (result == NULL)
++		error(1, errno, "out of memory");
+ 
+-int tun_fd = -1;
+-char tun_name[IFNAMSIZ];
++	result->sin_family = AF_INET;
++	result->sin_port = htons(port);
++	if (inet_aton(hostname, &result->sin_addr) == 0) {
++		hostinfo = gethostbyname(hostname);
++		if (hostinfo == NULL)
++			error(1, 0, "unknown host `%s'\n", hostname);
++		result->sin_addr = *(struct in_addr *)hostinfo->h_addr;
++	}
++	return (struct sockaddr *)result;
++}
+ 
+-static void
+-setup_tunnel(void)
++static void setup_tunnel(struct sa_block *s)
+ {
+-  if (config[CONFIG_IF_NAME]) 
+-	  memcpy(tun_name, config[CONFIG_IF_NAME], strlen(config[CONFIG_IF_NAME]));
+-  
+-  tun_fd = tun_open(tun_name);
+-  DEBUG(2,printf("using interface %s\n", tun_name));
++	if (config[CONFIG_IF_NAME])
++		memcpy(s->tun_name, config[CONFIG_IF_NAME], strlen(config[CONFIG_IF_NAME]));
+ 
+-  if (tun_fd == -1)
+-    error (1, errno, "can't initialise tunnel interface");
++	s->tun_fd = tun_open(s->tun_name);
++	DEBUG(2, printf("using interface %s\n", s->tun_name));
++
++	if (s->tun_fd == -1)
++		error(1, errno, "can't initialise tunnel interface");
+ }
+ 
+-static int sockfd = -1;
+-static struct sockaddr *dest_addr;
+-static int timeout = 5000;  /* 5 seconds */
+-static uint8_t *resend_hash = NULL;
++void config_tunnel(struct sa_block *s)
++{
++	setenv("TUNDEV", s->tun_name, 1);
++	setenv("VPNGATEWAY", inet_ntoa(((struct sockaddr_in *)dest_addr)->sin_addr), 1);
+ 
+-static int
+-recv_ignore_dup (void *recvbuf, size_t recvbufsize, uint8_t reply_extype)
++	system(config[CONFIG_CONFIG_SCRIPT]);
++}
++
++static int recv_ignore_dup(void *recvbuf, size_t recvbufsize, uint8_t reply_extype)
+ {
+-  uint8_t *resend_check_hash;
+-  int recvsize, hash_len;
+-  struct sockaddr_in recvaddr;
+-  socklen_t recvaddr_size = sizeof (recvaddr);
+-  char ntop_buf[32];
++	uint8_t *resend_check_hash;
++	int recvsize, hash_len;
++	struct sockaddr_in recvaddr;
++	socklen_t recvaddr_size = sizeof(recvaddr);
++	char ntop_buf[32];
+ 
+-  recvsize = recvfrom (sockfd, recvbuf, recvbufsize, 0,
+-		       (struct sockaddr *)&recvaddr, &recvaddr_size);
+-  if (recvsize == -1)
+-    error (1, errno, "receiving packet");
+-  if (recvsize > 0)
+-    {
+-      if (recvaddr_size != sizeof (recvaddr)
+-	  || recvaddr.sin_family != dest_addr->sa_family
+-	  || recvaddr.sin_port != ((struct sockaddr_in *)dest_addr)->sin_port
+-	  || memcmp (&recvaddr.sin_addr, 
+-		     &((struct sockaddr_in *)dest_addr)->sin_addr, 
+-		     sizeof (struct in_addr)) != 0)
+-	{
+-	  error (0, 0, "got response from unknown host %s:%d",
+-		 inet_ntop (recvaddr.sin_family, &recvaddr.sin_addr,
+-			    ntop_buf, sizeof (ntop_buf)),
+-		 ntohs (recvaddr.sin_port));
+-	  return -1;
+-	}
+-      
+-hex_dump("exchange_type", ((uint8_t*)recvbuf) + ISAKMP_EXCHANGE_TYPE_O, 1);
+-      if (reply_extype && (((uint8_t*)recvbuf)[ISAKMP_EXCHANGE_TYPE_O] != reply_extype)) {
+-DEBUG(2, printf("want extype %d, got %d, ignoring\n", reply_extype, ((uint8_t*)recvbuf)[ISAKMP_EXCHANGE_TYPE_O]));
+-	return -1;
+-      }
++	recvsize = recvfrom(sockfd, recvbuf, recvbufsize, 0,
++		(struct sockaddr *)&recvaddr, &recvaddr_size);
++	if (recvsize == -1)
++		error(1, errno, "receiving packet");
++	if (recvsize > 0) {
++		if (recvaddr_size != sizeof(recvaddr)
++			|| recvaddr.sin_family != dest_addr->sa_family
++			|| recvaddr.sin_port != ((struct sockaddr_in *)dest_addr)->sin_port
++			|| memcmp(&recvaddr.sin_addr,
++				&((struct sockaddr_in *)dest_addr)->sin_addr,
++				sizeof(struct in_addr)) != 0) {
++			error(0, 0, "got response from unknown host %s:%d",
++				inet_ntop(recvaddr.sin_family, &recvaddr.sin_addr,
++					ntop_buf, sizeof(ntop_buf)), ntohs(recvaddr.sin_port));
++			return -1;
++		}
+ 
+-      hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
+-      resend_check_hash = malloc(hash_len);
+-      gcry_md_hash_buffer(GCRY_MD_SHA1, resend_check_hash, recvbuf, recvsize);
+-      if (resend_hash && memcmp(resend_hash, resend_check_hash, hash_len) == 0) {
+-	free(resend_check_hash);
+-	return -1;
+-      }
+-      if (!resend_hash) {
+-	resend_hash = resend_check_hash;
+-      } else {
+-	memcpy (resend_hash, resend_check_hash, hash_len);
+-	free(resend_check_hash);
+-      }
+-    }
+-  return recvsize;
++		hex_dump("exchange_type", ((uint8_t *) recvbuf) + ISAKMP_EXCHANGE_TYPE_O, UINT8);
++		if (reply_extype && (((uint8_t *) recvbuf)[ISAKMP_EXCHANGE_TYPE_O] != reply_extype)) {
++			DEBUG(2, printf("want extype %d, got %d, ignoring\n", reply_extype,
++					((uint8_t *) recvbuf)[ISAKMP_EXCHANGE_TYPE_O]));
++			return -1;
++		}
++
++		hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
++		resend_check_hash = malloc(hash_len);
++		gcry_md_hash_buffer(GCRY_MD_SHA1, resend_check_hash, recvbuf, recvsize);
++		if (resend_hash && memcmp(resend_hash, resend_check_hash, hash_len) == 0) {
++			free(resend_check_hash);
++			return -1;
++		}
++		if (!resend_hash) {
++			resend_hash = resend_check_hash;
++		} else {
++			memcpy(resend_hash, resend_check_hash, hash_len);
++			free(resend_check_hash);
++		}
++	}
++	return recvsize;
+ }
+ 
+ /* Send TOSEND of size SENDSIZE to the socket.  Then wait for a new packet,
+@@ -335,2075 +305,1611 @@
+    of the new packet is returned.  */
+ 
+ static ssize_t
+-sendrecv (void *recvbuf, size_t recvbufsize, void *tosend, size_t sendsize, uint8_t reply_extype)
++sendrecv(void *recvbuf, size_t recvbufsize, void *tosend, size_t sendsize, uint8_t reply_extype)
+ {
+-  struct pollfd pfd;
+-  int tries = 0;
+-  int recvsize;
+-  time_t start = time (NULL);
+-  time_t end;
+-  
+-  pfd.fd = sockfd;
+-  pfd.events = POLLIN;
+-  tries = 0;
+-  
+-  for (;;)
+-    {
+-      int pollresult;
+-      
+-      if (tosend != NULL)
+-        if (sendto (sockfd, tosend, sendsize, 0,
+-		  dest_addr, sizeof (struct sockaddr_in)) != (int) sendsize)
+-	  error (1, errno, "can't send packet");
+-      do {
+-	pollresult = poll (&pfd, 1, timeout << tries);
+-      } while (pollresult == -1 && errno == EINTR);
+-      if (pollresult == -1)
+-	error (1, errno, "can't poll socket");
+-      if (pollresult != 0)
+-	{
+-	  recvsize = recv_ignore_dup (recvbuf, recvbufsize, reply_extype);
+-	  end = time (NULL);
+-	  if (recvsize != -1)
+-	    break;
+-	  continue;
++	struct pollfd pfd;
++	int tries = 0;
++	int recvsize;
++	time_t start = time(NULL);
++	time_t end;
++
++	pfd.fd = sockfd;
++	pfd.events = POLLIN;
++	tries = 0;
++
++	for (;;) {
++		int pollresult;
++
++		if (tosend != NULL)
++			if (sendto(sockfd, tosend, sendsize, 0,
++					dest_addr, sizeof(struct sockaddr_in)) != (int)sendsize)
++				error(1, errno, "can't send packet");
++		do {
++			pollresult = poll(&pfd, 1, timeout << tries);
++		} while (pollresult == -1 && errno == EINTR);
++		if (pollresult == -1)
++			error(1, errno, "can't poll socket");
++		if (pollresult != 0) {
++			recvsize = recv_ignore_dup(recvbuf, recvbufsize, reply_extype);
++			end = time(NULL);
++			if (recvsize != -1)
++				break;
++			continue;
++		}
++		if (tries > 5)
++			error(1, 0, "no response from target");
++		tries++;
+ 	}
+-      if (tries > 5)
+-	error (1, 0, "no response from target");
+-      tries++;
+-    }
+ 
+-  /* Wait at least 2s for a response or 4 times the time it took
+-     last time.  */
+-  if (start == end)
+-    timeout = 2000;
+-  else
+-    timeout = 4000 * (end - start);
++	/* Wait at least 2s for a response or 4 times the time it took
++	 * last time.  */
++	if (start == end)
++		timeout = 2000;
++	else
++		timeout = 4000 * (end - start);
+ 
+-  return recvsize;
++	return recvsize;
+ }
+ 
+-struct isakmp_attribute *
+-make_transform_ike(int dh_group, int crypt, int hash, int keylen)
++void isakmp_crypt(struct sa_block *s, uint8_t * block, size_t blocklen, int enc)
+ {
+-  struct isakmp_attribute *a = NULL;
+-  
+-  a = new_isakmp_attribute (IKE_ATTRIB_LIFE_DURATION, a);
+-  a->af = isakmp_attr_lots;
+-  a->u.lots.length = 4;
+-  a->u.lots.data = xallocc(a->u.lots.length);
+-  *((uint32_t *)a->u.lots.data) = htonl(2147483);
+-  a = new_isakmp_attribute_16 (IKE_ATTRIB_LIFE_TYPE, IKE_LIFE_TYPE_SECONDS, a);
+-  a = new_isakmp_attribute_16 (IKE_ATTRIB_GROUP_DESC, dh_group, a);
+-  a = new_isakmp_attribute_16 (IKE_ATTRIB_AUTH_METHOD, 
+-			       XAUTH_AUTH_XAUTHInitPreShared, a);
+-  a = new_isakmp_attribute_16 (IKE_ATTRIB_HASH, hash, a);
+-  a = new_isakmp_attribute_16 (IKE_ATTRIB_ENC, crypt, a);
+-  if (keylen != 0)
+-    a = new_isakmp_attribute_16 (IKE_ATTRIB_KEY_LENGTH,
+-				 keylen, a);
+-  return a;
+-}
++	unsigned char *new_iv;
++	gcry_cipher_hd_t cry_ctx;
+ 
+-struct isakmp_payload *
+-make_our_sa_ike (void)
+-{
+-  struct isakmp_payload *r = new_isakmp_payload (ISAKMP_PAYLOAD_SA);
+-  struct isakmp_payload *t = NULL, *tn;
+-  struct isakmp_attribute *a;
+-  int dh_grp = get_dh_group_ike()->ike_sa_id;
+-  unsigned int crypt, hash, keylen;
+-  int i;
+-  
+-  r->u.sa.doi = ISAKMP_DOI_IPSEC;
+-  r->u.sa.situation = ISAKMP_IPSEC_SIT_IDENTITY_ONLY;
+-  r->u.sa.proposals = new_isakmp_payload (ISAKMP_PAYLOAD_P);
+-  r->u.sa.proposals->u.p.prot_id = ISAKMP_IPSEC_PROTO_ISAKMP;
+-  for (crypt = 0; crypt < sizeof(supp_crypt) / sizeof(supp_crypt[0]); crypt++) {
+-    if ((supp_crypt[crypt].my_id == GCRY_CIPHER_DES)&&(opt_1des == 0))
+-      continue;
+-    keylen = supp_crypt[crypt].keylen;
+-    for (hash = 0; hash < sizeof(supp_hash) / sizeof(supp_hash[0]); hash++) {
+-      tn = t;
+-      t = new_isakmp_payload (ISAKMP_PAYLOAD_T);
+-      t->u.t.id = ISAKMP_IPSEC_KEY_IKE;
+-      a = make_transform_ike(dh_grp, supp_crypt[crypt].ike_sa_id,
+-			 supp_hash[hash].ike_sa_id, keylen);
+-      t->u.t.attributes = a;
+-      t->next = tn;
+-    }
+-  }
+-  for (i = 0, tn = t; tn; tn = tn->next)
+-      tn->u.t.number = i++;
+-  r->u.sa.proposals->u.p.transforms = t;
+-  return r;
+-}
++	if (blocklen < ISAKMP_PAYLOAD_O || ((blocklen - ISAKMP_PAYLOAD_O) % s->ivlen != 0))
++		abort();
+ 
+-struct sa_block 
+-{
+-  uint8_t i_cookie[ISAKMP_COOKIE_LENGTH];
+-  uint8_t r_cookie[ISAKMP_COOKIE_LENGTH];
+-  uint8_t *key;
+-  int keylen;
+-  uint8_t *initial_iv;
+-  uint8_t *skeyid_a;
+-  uint8_t *skeyid_d;
+-  int cry_algo, ivlen;
+-  int md_algo, md_len;
+-  uint8_t current_iv_msgid[4];
+-  uint8_t *current_iv;
+-  uint8_t our_address[4], our_netmask[4];
+-  uint32_t tous_esp_spi, tothem_esp_spi;
+-  uint8_t *kill_packet;
+-  size_t kill_packet_size;
+-  int do_pfs;
+-};
++	if ((memcmp(block + ISAKMP_MESSAGE_ID_O, s->current_iv_msgid, 4) != 0) && (enc >= 0)) {
++		unsigned char *iv;
++		gcry_md_hd_t md_ctx;
+ 
+-void
+-isakmp_crypt (struct sa_block *s, uint8_t *block, size_t blocklen, int enc)
+-{
+-  unsigned char *new_iv;
+-  gcry_cipher_hd_t cry_ctx;
+-  
+-  if (blocklen < ISAKMP_PAYLOAD_O 
+-      || ((blocklen - ISAKMP_PAYLOAD_O) % s->ivlen != 0))
+-    abort ();
++		gcry_md_open(&md_ctx, s->md_algo, 0);
++		gcry_md_write(md_ctx, s->initial_iv, s->ivlen);
++		gcry_md_write(md_ctx, block + ISAKMP_MESSAGE_ID_O, 4);
++		gcry_md_final(md_ctx);
++		iv = gcry_md_read(md_ctx, 0);
++		memcpy(s->current_iv, iv, s->ivlen);
++		memcpy(s->current_iv_msgid, block + ISAKMP_MESSAGE_ID_O, 4);
++		gcry_md_close(md_ctx);
++	}
+ 
+-  if ((memcmp (block + ISAKMP_MESSAGE_ID_O, s->current_iv_msgid, 4) != 0)&&(enc >= 0))
+-    {
+-      unsigned char *iv;
+-      gcry_md_hd_t md_ctx;
+-      
+-       gcry_md_open(&md_ctx, s->md_algo, 0);
+-      gcry_md_write(md_ctx, s->initial_iv, s->ivlen);
+-      gcry_md_write(md_ctx, block + ISAKMP_MESSAGE_ID_O, 4);
+-      gcry_md_final(md_ctx);
+-      iv = gcry_md_read(md_ctx, 0);
+-      memcpy (s->current_iv, iv, s->ivlen);
+-      memcpy (s->current_iv_msgid, block + ISAKMP_MESSAGE_ID_O, 4);
+-      gcry_md_close(md_ctx);
+-    }
++	new_iv = xallocc(s->ivlen);
++	gcry_cipher_open(&cry_ctx, s->cry_algo, GCRY_CIPHER_MODE_CBC, 0);
++	gcry_cipher_setkey(cry_ctx, s->key, s->keylen);
++	gcry_cipher_setiv(cry_ctx, s->current_iv, s->ivlen);
++	if (!enc) {
++		memcpy(new_iv, block + blocklen - s->ivlen, s->ivlen);
++		gcry_cipher_decrypt(cry_ctx, block + ISAKMP_PAYLOAD_O, blocklen - ISAKMP_PAYLOAD_O,
++			NULL, 0);
++		memcpy(s->current_iv, new_iv, s->ivlen);
++	} else { /* enc == -1 (no longer used) || enc == 1 */
++		gcry_cipher_encrypt(cry_ctx, block + ISAKMP_PAYLOAD_O, blocklen - ISAKMP_PAYLOAD_O,
++			NULL, 0);
++		if (enc > 0)
++			memcpy(s->current_iv, block + blocklen - s->ivlen, s->ivlen);
++	}
++	gcry_cipher_close(cry_ctx);
+ 
+-  new_iv = xallocc (s->ivlen);
+-  gcry_cipher_open(&cry_ctx, s->cry_algo, GCRY_CIPHER_MODE_CBC, 0);
+-  gcry_cipher_setkey(cry_ctx, s->key, s->keylen);
+-  gcry_cipher_setiv(cry_ctx, s->current_iv, s->ivlen);
+-  if (!enc) {
+-    memcpy (new_iv, block + blocklen - s->ivlen, s->ivlen);
+-    gcry_cipher_decrypt(cry_ctx, block + ISAKMP_PAYLOAD_O, blocklen - ISAKMP_PAYLOAD_O, NULL, 0);
+-    memcpy (s->current_iv, new_iv, s->ivlen);
+-  } else { /* enc == -1 (no longer used) || enc == 1 */
+-    gcry_cipher_encrypt(cry_ctx, block + ISAKMP_PAYLOAD_O, blocklen - ISAKMP_PAYLOAD_O, NULL, 0);
+-    if (enc > 0)
+-      memcpy (s->current_iv, block + blocklen - s->ivlen, s->ivlen);
+-  }
+-  gcry_cipher_close(cry_ctx);
+-  
+ }
+ 
+-static uint8_t r_packet[2048];
+-static ssize_t r_length;
+-
+-void
+-do_phase_1 (const char *key_id, const char *shared_key,
+-	    struct sa_block *d)
++static uint16_t unpack_verify_phase2(struct sa_block *s,
++	uint8_t * r_packet,
++	size_t r_length, struct isakmp_packet **r_p, const uint8_t * nonce, size_t nonce_size)
+ {
+-  unsigned char i_nonce[20];
+-  struct group *dh_grp;
+-  unsigned char *dh_public;
+-  unsigned char *returned_hash;
+-  static const uint8_t xauth_vid[] = XAUTH_VENDOR_ID;
+-  static const uint8_t unity_vid[] = UNITY_VENDOR_ID;
+-  static const uint8_t unknown_vid[] = UNKNOWN_VENDOR_ID;
+-#if 0
+-  static const uint8_t dpd_vid[] = UNITY_VENDOR_ID;
+-  static const uint8_t my_vid[] = { 
+-    0x35, 0x53, 0x07, 0x6c, 0x4f, 0x65, 0x12, 0x68, 0x02, 0x82, 0xf2, 0x15,
+-    0x8a, 0xa8, 0xa0, 0x9e };
+-#endif
+-  
+-  struct isakmp_packet *p1;
+-  
+-DEBUG(2, printf("S4.1\n"));
+-  gcry_randomize(d->i_cookie, ISAKMP_COOKIE_LENGTH, GCRY_STRONG_RANDOM);
+-  d->do_pfs = -1;
+-  if (d->i_cookie[0] == 0)
+-    d->i_cookie[0] = 1;
+-hex_dump("i_cookie", d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-  gcry_randomize(i_nonce, sizeof (i_nonce), GCRY_STRONG_RANDOM);
+-hex_dump("i_nonce", i_nonce, sizeof (i_nonce));
+-DEBUG(2, printf("S4.2\n"));
+-  /* Set up the Diffie-Hellman stuff.  */
+-  {
+-    dh_grp = group_get(get_dh_group_ike()->my_id);
+-    dh_public = xallocc(dh_getlen (dh_grp));
+-    dh_create_exchange(dh_grp, dh_public);
+-hex_dump("dh_public", dh_public, dh_getlen (dh_grp));
+-  }
+-  
+-DEBUG(2, printf("S4.3\n"));
+-  /* Create the first packet.  */
+-  {
+-    struct isakmp_payload *l;
+-    uint8_t *pkt;
+-    size_t pkt_len;
++	struct isakmp_packet *r;
++	uint16_t reject = 0;
+ 
+-    p1 = new_isakmp_packet();
+-    memcpy (p1->i_cookie, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-    p1->isakmp_version = ISAKMP_VERSION;
+-    p1->exchange_type = ISAKMP_EXCHANGE_AGGRESSIVE;
+-    p1->payload = l = make_our_sa_ike();
+-    l->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_KE,
+-				       dh_public, dh_getlen (dh_grp));
+-    l->next->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_NONCE,
+-					     i_nonce, sizeof (i_nonce));
+-    l = l->next->next;
+-    l->next = new_isakmp_payload (ISAKMP_PAYLOAD_ID);
+-    l = l->next;
+-    l->u.id.type = ISAKMP_IPSEC_ID_KEY_ID;
+-    l->u.id.protocol = IPPROTO_UDP;
+-    l->u.id.port = 500; /*TODO: get local port */
+-    l->u.id.length = strlen (key_id);
+-    l->u.id.data = xallocc (l->u.id.length);
+-    memcpy (l->u.id.data, key_id, strlen (key_id));
+-    l->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_VID,
+-				       xauth_vid, sizeof (xauth_vid));
+-    l->next->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_VID,
+-					     unity_vid, sizeof (unity_vid));
+-#if 0
+-    l->next->next->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_VID,
+-						   dpd_vid, sizeof (dpd_vid));
+-#endif
+-    flatten_isakmp_packet (p1, &pkt, &pkt_len, 0);
++	*r_p = NULL;
+ 
+-    /* Now, send that packet and receive a new one.  */
+-    r_length = sendrecv (r_packet, sizeof (r_packet), 
+-			 pkt, pkt_len, 0);
+-    free (pkt);
+-  }
+-DEBUG(2, printf("S4.4\n"));
+-  /* Decode the recieved packet.  */
+-  {
+-     struct isakmp_packet *r;
+-     uint16_t reject;
+-     struct isakmp_payload *rp;
+-     struct isakmp_payload *nonce = NULL;
+-     struct isakmp_payload *ke = NULL;
+-     struct isakmp_payload *hash = NULL;
+-     struct isakmp_payload *idp = NULL;
+-     int seen_xauth_vid = 0;
+-     unsigned char *skeyid;
+-     gcry_md_hd_t skeyid_ctx;
+-     
+-     reject = 0;
+-     r = parse_isakmp_packet (r_packet, r_length, &reject);
++	if (r_length < ISAKMP_PAYLOAD_O || ((r_length - ISAKMP_PAYLOAD_O) % s->ivlen != 0))
++		return ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
+ 
+-     /* Verify the correctness of the recieved packet.  */
+-     if (reject == 0 && 
+-	 memcmp (r->i_cookie, d->i_cookie, ISAKMP_COOKIE_LENGTH) != 0)
+-       reject = ISAKMP_N_INVALID_COOKIE;
+-     if (reject == 0)
+-       memcpy (d->r_cookie, r->r_cookie, ISAKMP_COOKIE_LENGTH);
+-     if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_AGGRESSIVE)
+-       reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
+-     if (reject == 0 && r->flags != 0)
+-       reject = ISAKMP_N_INVALID_FLAGS;
+-     if (reject == 0 && r->message_id != 0)
+-       reject = ISAKMP_N_INVALID_MESSAGE_ID;
+-     if (reject != 0)
+-       error (1, 0, "response was invalid [1]: %s", 
+-	      isakmp_notify_to_error (reject));
+-     for (rp = r->payload; rp && reject == 0; rp = rp->next)
+-       switch (rp->type)
+-	 {
+-	 case ISAKMP_PAYLOAD_SA:
+-	   if (reject == 0 && rp->u.sa.doi != ISAKMP_DOI_IPSEC)
+-	     reject = ISAKMP_N_DOI_NOT_SUPPORTED;
+-	   if (reject == 0 && 
+-	       rp->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY)
+-	     reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
+-	   if (reject == 0 && 
+-	       (rp->u.sa.proposals == NULL
+-		|| rp->u.sa.proposals->next != NULL))
+-	     reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	   if (reject == 0 &&
+-	       rp->u.sa.proposals->u.p.prot_id != ISAKMP_IPSEC_PROTO_ISAKMP)
+-	     reject = ISAKMP_N_INVALID_PROTOCOL_ID;
+-	   if (reject == 0 &&
+-	       rp->u.sa.proposals->u.p.spi_size != 0)
+-	     reject = ISAKMP_N_INVALID_SPI;
+-	   if (reject == 0 &&
+-	       (rp->u.sa.proposals->u.p.transforms == NULL
+-		|| rp->u.sa.proposals->u.p.transforms->next != NULL))
+-	     reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	   if (reject == 0 &&
+-	       (rp->u.sa.proposals->u.p.transforms->u.t.id 
+-		!= ISAKMP_IPSEC_KEY_IKE))
+-	     reject = ISAKMP_N_INVALID_TRANSFORM_ID;
+-	   if (reject == 0) {
+-	     struct isakmp_attribute *a 
+-	       = rp->u.sa.proposals->u.p.transforms->u.t.attributes;
+-	     int seen_enc = 0, seen_hash = 0, seen_auth = 0;
+-	     int seen_group = 0, seen_keylen = 0;
+-	     for (; a && reject == 0; a = a->next)
+-	       switch (a->type)
+-		 {
+-		   case IKE_ATTRIB_GROUP_DESC: 
+-		     if (a->af == isakmp_attr_16 &&
+-			 a->u.attr_16 == get_dh_group_ike()->ike_sa_id)
+-		       seen_group = 1;
+-		     else
+-		       reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		     break;
+-		   case IKE_ATTRIB_AUTH_METHOD: 
+-		     if (a->af == isakmp_attr_16 &&
+-			 a->u.attr_16 == XAUTH_AUTH_XAUTHInitPreShared)
+-		       seen_auth = 1;
+-		     else
+-		       reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		     break;
+-		   case IKE_ATTRIB_HASH: 
+-		     if (a->af == isakmp_attr_16)
+-		       seen_hash = a->u.attr_16;
+-		     else
+-		       reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		     break;
+-		   case IKE_ATTRIB_ENC: 
+-		     if (a->af == isakmp_attr_16)
+-		       seen_enc = a->u.attr_16;
+-		     else
+-		       reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		     break;
+-		   case IKE_ATTRIB_KEY_LENGTH: 
+-		     if (a->af == isakmp_attr_16)
+-		       seen_keylen = a->u.attr_16;
+-		     else
+-		       reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		     break;
+-		   case IKE_ATTRIB_LIFE_TYPE:
+-		   case IKE_ATTRIB_LIFE_DURATION:
+-		     break;
+-		 default:
+-		     DEBUG(1, printf("unknown attribute %d, arborting..\n", a->type));
+-		     reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-		     break;
+-		 }
+-	     if (! seen_group || ! seen_auth || ! seen_hash || ! seen_enc)
+-	       reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	     
+-	     if (get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IKE_SA, seen_hash, NULL, 0) == NULL)
+-	       reject = ISAKMP_N_NO_PROPOSAL_CHOSEN;
+-	     if (get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IKE_SA, seen_enc, NULL, seen_keylen) == NULL)
+-	       reject = ISAKMP_N_NO_PROPOSAL_CHOSEN;
+-	     
+-	     if (reject == 0) {
+-	       d->cry_algo = get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IKE_SA,
+-			     seen_enc, NULL, seen_keylen)->my_id;
+-	       d->md_algo = get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IKE_SA,
+-			     seen_hash, NULL, 0)->my_id;
+-	       DEBUG(1, printf("IKE SA selected %s-%s\n",
+-			    get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IKE_SA,
+-				    seen_enc, NULL, seen_keylen)->name,
+-			    get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IKE_SA,
+-				    seen_hash, NULL, 0)->name));
+-	     }
+-	   }
+-	   break;
++	isakmp_crypt(s, r_packet, r_length, 0);
+ 
+-	 case ISAKMP_PAYLOAD_ID:	idp   = rp; break;
+-	 case ISAKMP_PAYLOAD_KE:	ke    = rp; break;
+-	 case ISAKMP_PAYLOAD_NONCE:	nonce = rp; break;
+-	 case ISAKMP_PAYLOAD_HASH:	hash  = rp; break;
+-	 case ISAKMP_PAYLOAD_VID:
+-	   if (rp->u.vid.length == sizeof (xauth_vid)
+-	       && memcmp (rp->u.vid.data, xauth_vid, sizeof (xauth_vid)) == 0)
+-	     seen_xauth_vid = 1;
+-	   break;
+-	 default:
+-	   reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-	   break;
+-	 }
++	{
++		r = parse_isakmp_packet(r_packet, r_length, &reject);
++		if (reject != 0)
++			return reject;
++	}
+ 
+-     if (reject == 0) {
+-        d->md_len = gcry_md_get_algo_dlen(d->md_algo);
+-        gcry_cipher_algo_info(d->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(d->ivlen));
+-        gcry_cipher_algo_info(d->cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(d->keylen));
+-     }
++	/* Verify the basic stuff.  */
++	if (memcmp(r->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH) != 0
++		|| memcmp(r->r_cookie, s->r_cookie, ISAKMP_COOKIE_LENGTH) != 0)
++		return ISAKMP_N_INVALID_COOKIE;
++	if (r->flags != ISAKMP_FLAG_E)
++		return ISAKMP_N_INVALID_FLAGS;
+ 
+-     if (reject == 0
+-	 && (ke == NULL || ke->u.ke.length != dh_getlen (dh_grp)))
+-       reject = ISAKMP_N_INVALID_KEY_INFORMATION;
+-     if (reject == 0 && nonce == NULL)
+-       reject = ISAKMP_N_INVALID_HASH_INFORMATION;
+-     if (reject != 0)
+-       error (1, 0, "response was invalid [2]: %s", 
+-	      isakmp_notify_to_error (reject));
+-     if (reject == 0 && idp == NULL)
+-       reject = ISAKMP_N_INVALID_ID_INFORMATION;
+-     if (reject == 0 && (hash == NULL 
+-			 || hash->u.hash.length != d->md_len))
+-       reject = ISAKMP_N_INVALID_HASH_INFORMATION;
+-     if (reject != 0)
+-       error (1, 0, "response was invalid [3]: %s", 
+-	      isakmp_notify_to_error (reject));
++	{
++		size_t sz, spos;
++		gcry_md_hd_t hm;
++		unsigned char *expected_hash;
++		struct isakmp_payload *h = r->payload;
+ 
+-     /* Generate SKEYID.  */
+-     {
+-       gcry_md_open(&skeyid_ctx, d->md_algo, GCRY_MD_FLAG_HMAC);
+-       gcry_md_setkey(skeyid_ctx, shared_key, strlen (shared_key));
+-       gcry_md_write(skeyid_ctx, i_nonce, sizeof (i_nonce));
+-       gcry_md_write(skeyid_ctx, nonce->u.nonce.data, nonce->u.nonce.length);
+-       gcry_md_final(skeyid_ctx);
+-       skeyid = gcry_md_read(skeyid_ctx, 0);
+-hex_dump("skeyid", skeyid, d->md_len);
+-     }
++		if (h == NULL || h->type != ISAKMP_PAYLOAD_HASH || h->u.hash.length != s->md_len)
++			return ISAKMP_N_INVALID_HASH_INFORMATION;
+ 
+-     /* Verify the hash.  */
+-     {
+-       gcry_md_hd_t hm;
+-       unsigned char *expected_hash;
+-       uint8_t *sa_f, *idi_f, *idp_f;
+-       size_t sa_size, idi_size, idp_size;
+-       struct isakmp_payload *sa, *idi;
++		spos = (ISAKMP_PAYLOAD_O + (r_packet[ISAKMP_PAYLOAD_O + 2] << 8)
++			+ r_packet[ISAKMP_PAYLOAD_O + 3]);
+ 
+-       sa = p1->payload;
+-       for (idi = sa; idi->type != ISAKMP_PAYLOAD_ID; idi = idi->next)
+-	 ;
+-       sa->next = NULL;
+-       idi->next = NULL;
+-       idp->next = NULL;
+-       flatten_isakmp_payload (sa, &sa_f, &sa_size);
+-       flatten_isakmp_payload (idi, &idi_f, &idi_size);
+-       flatten_isakmp_payload (idp, &idp_f, &idp_size);
++		/* Compute the real length based on the payload lengths.  */
++		for (sz = spos; r_packet[sz] != 0; sz += r_packet[sz + 2] << 8 | r_packet[sz + 3]) ;
++		sz += r_packet[sz + 2] << 8 | r_packet[sz + 3];
+ 
+-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
+-       gcry_md_setkey(hm, skeyid, d->md_len);
+-       gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
+-       gcry_md_write(hm, dh_public, dh_getlen (dh_grp));
+-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, sa_f + 4, sa_size - 4);
+-       gcry_md_write(hm, idp_f + 4, idp_size - 4);
+-       gcry_md_final(hm);
+-       expected_hash = gcry_md_read(hm, 0);
+-       
+-       if (memcmp (expected_hash, hash->u.hash.data, d->md_len) != 0)
+-	 {
+-	   error (1, 0, "hash comparison failed: %s\ncheck group password!", 
+-		  isakmp_notify_to_error (ISAKMP_N_AUTHENTICATION_FAILED));
+-	 }
+-       gcry_md_close(hm);
++		gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++		gcry_md_setkey(hm, s->skeyid_a, s->md_len);
++		gcry_md_write(hm, r_packet + ISAKMP_MESSAGE_ID_O, 4);
++		if (nonce)
++			gcry_md_write(hm, nonce, nonce_size);
++		gcry_md_write(hm, r_packet + spos, sz - spos);
++		gcry_md_final(hm);
++		expected_hash = gcry_md_read(hm, 0);
+ 
+-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
+-       gcry_md_setkey(hm, skeyid, d->md_len);
+-       gcry_md_write(hm, dh_public, dh_getlen (dh_grp));
+-       gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
+-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, sa_f + 4, sa_size - 4);
+-       gcry_md_write(hm, idi_f + 4, idi_size - 4);
+-       gcry_md_final(hm);
+-       returned_hash = xallocc(d->md_len);
+-       memcpy(returned_hash, gcry_md_read(hm, 0), d->md_len);
+-       gcry_md_close(hm);
+-hex_dump("returned_hash", returned_hash, d->md_len);
+-       
+-       free (sa_f);
+-       free (idi);
+-       free (idp);
+-     }
++		if (opt_debug >= 3) {
++			printf("hashlen: %d\n", s->md_len);
++			printf("u.hash.length: %d\n", h->u.hash.length);
++			hex_dump("expected_hash", expected_hash, s->md_len);
++			hex_dump("h->u.hash.data", h->u.hash.data, s->md_len);
++		}
+ 
+-     /* Determine all the SKEYID_x keys.  */
+-     {
+-       gcry_md_hd_t hm;
+-       int i;
+-       static const unsigned char c012[3] = { 0, 1, 2 };
+-       unsigned char *skeyid_e;
+-       unsigned char *dh_shared_secret;
++		reject = 0;
++		if (memcmp(h->u.hash.data, expected_hash, s->md_len) != 0)
++			reject = ISAKMP_N_AUTHENTICATION_FAILED;
++		gcry_md_close(hm);
++#if 0
++		if (reject != 0)
++			return reject;
++#endif
++	}
++	*r_p = r;
++	return 0;
++}
+ 
+-       /* Determine the shared secret.  */
+-       dh_shared_secret = xallocc(dh_getlen (dh_grp));
+-       dh_create_shared (dh_grp, dh_shared_secret, ke->u.ke.data);
+-hex_dump("dh_shared_secret", dh_shared_secret, dh_getlen (dh_grp));
++static void
++phase2_authpacket(struct sa_block *s, struct isakmp_payload *pl,
++	uint8_t exchange_type, uint32_t msgid,
++	uint8_t ** p_flat, size_t * p_size,
++	uint8_t * nonce_i, int ni_len, uint8_t * nonce_r, int nr_len)
++{
++	struct isakmp_packet *p;
++	uint8_t *pl_flat;
++	size_t pl_size;
++	gcry_md_hd_t hm;
++	uint8_t msgid_sent[4];
+ 
+-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
+-       gcry_md_setkey(hm, skeyid, d->md_len);
+-       gcry_md_write(hm, dh_shared_secret, dh_getlen (dh_grp));
+-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, c012+0, 1);
+-       gcry_md_final(hm);
+-       d->skeyid_d = xallocc(d->md_len);
+-       memcpy(d->skeyid_d, gcry_md_read(hm, 0), d->md_len);
+-       gcry_md_close(hm);
+-hex_dump("skeyid_d", d->skeyid_d, d->md_len);
+-       
+-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
+-       gcry_md_setkey(hm, skeyid, d->md_len);
+-       gcry_md_write(hm, d->skeyid_d, d->md_len);
+-       gcry_md_write(hm, dh_shared_secret, dh_getlen (dh_grp));
+-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, c012+1, 1);
+-       gcry_md_final(hm);
+-       d->skeyid_a = xallocc(d->md_len);
+-       memcpy(d->skeyid_a, gcry_md_read(hm, 0), d->md_len);
+-       gcry_md_close(hm);
+-hex_dump("skeyid_a", d->skeyid_a, d->md_len);
+-       
+-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
+-       gcry_md_setkey(hm, skeyid, d->md_len);
+-       gcry_md_write(hm, d->skeyid_a, d->md_len);
+-       gcry_md_write(hm, dh_shared_secret, dh_getlen (dh_grp));
+-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-       gcry_md_write(hm, c012+2, 1);
+-       gcry_md_final(hm);
+-       skeyid_e = xallocc(d->md_len);
+-       memcpy(skeyid_e, gcry_md_read(hm, 0), d->md_len);
+-       gcry_md_close(hm);
+-hex_dump("skeyid_e", skeyid_e, d->md_len);
++	/* Build up the packet.  */
++	p = new_isakmp_packet();
++	memcpy(p->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++	memcpy(p->r_cookie, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++	p->flags = ISAKMP_FLAG_E;
++	p->isakmp_version = ISAKMP_VERSION;
++	p->exchange_type = exchange_type;
++	p->message_id = msgid;
++	p->payload = new_isakmp_payload(ISAKMP_PAYLOAD_HASH);
++	p->payload->next = pl;
++	p->payload->u.hash.length = s->md_len;
++	p->payload->u.hash.data = xallocc(s->md_len);
+ 
+-       memset (dh_shared_secret, 0, sizeof (dh_shared_secret));
++	/* Set the MAC.  */
++	gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++	gcry_md_setkey(hm, s->skeyid_a, s->md_len);
+ 
+-       /* Determine the IKE encryption key.  */
+-       d->key = xallocc(d->keylen);
+-       
+-       if (d->keylen > d->md_len) {
+-         for (i = 0; i * d->md_len < d->keylen; i++) {
+-           gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
+-           gcry_md_setkey(hm, skeyid_e, d->md_len);
+-	   if (i == 0)
+-             gcry_md_write(hm, "" /* &'\0' */, 1);
+-	   else
+-             gcry_md_write(hm, d->key + (i-1) * d->md_len, d->md_len);
+-           gcry_md_final(hm);
+-           memcpy(d->key + i * d->md_len, gcry_md_read(hm, 0),
+-		  min(d->md_len, d->keylen - i*d->md_len));
+-           gcry_md_close(hm);
+-         }
+-       } else { /* keylen <= md_len*/
+-           memcpy(d->key, skeyid_e, d->keylen);
+-       }
+-hex_dump("enc-key", d->key, d->keylen);
+-       
+-       memset (skeyid_e, 0, d->md_len);
+-     }
++	if (pl == NULL) {
++		DEBUG(3, printf("authing NULL package!\n"));
++		gcry_md_write(hm, "" /* \0 */ , 1);
++	}
+ 
+-     /* Determine the initial 3DES IV.  */
+-     {
+-       gcry_md_hd_t hm;
+-       
+-       assert(d->ivlen < d->md_len);
+-       gcry_md_open(&hm, d->md_algo, 0);
+-       gcry_md_write(hm, dh_public, dh_getlen (dh_grp));
+-       gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
+-       gcry_md_final(hm);
+-       d->current_iv = xallocc(d->ivlen);
+-       memcpy(d->current_iv, gcry_md_read(hm, 0), d->ivlen);
+-       gcry_md_close(hm);
+-hex_dump("current_iv", d->current_iv, d->ivlen);
+-       memset (d->current_iv_msgid, 0, 4);
+-     }
+-     
+-     gcry_md_close(skeyid_ctx);
+-  }
++	msgid_sent[0] = msgid >> 24;
++	msgid_sent[1] = msgid >> 16;
++	msgid_sent[2] = msgid >> 8;
++	msgid_sent[3] = msgid;
++	gcry_md_write(hm, msgid_sent, sizeof(msgid_sent));
+ 
+-DEBUG(2, printf("S4.5\n"));
+-  /* Send final phase 1 packet.  */
+-  {
+-    struct isakmp_packet *p2;
+-    uint8_t *p2kt;
+-    size_t p2kt_len;
+-    struct isakmp_payload *pl;
+-    
+-    p2 = new_isakmp_packet ();
+-    memcpy (p2->i_cookie, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-    memcpy (p2->r_cookie, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-    p2->flags = ISAKMP_FLAG_E;
+-    p2->isakmp_version = ISAKMP_VERSION;
+-    p2->exchange_type = ISAKMP_EXCHANGE_AGGRESSIVE;
+-    p2->payload = new_isakmp_data_payload (ISAKMP_PAYLOAD_HASH,
+-					   returned_hash, 
+-					   d->md_len);
+-    p2->payload->next = pl = new_isakmp_payload (ISAKMP_PAYLOAD_N);
+-    pl->u.n.doi = ISAKMP_DOI_IPSEC;
+-    pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
+-    pl->u.n.type = ISAKMP_N_IPSEC_INITIAL_CONTACT;
+-    pl->u.n.spi_length = 2*ISAKMP_COOKIE_LENGTH;
+-    pl->u.n.spi = xallocc(2*ISAKMP_COOKIE_LENGTH);
+-    memcpy(pl->u.n.spi+ISAKMP_COOKIE_LENGTH*0, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+-    memcpy(pl->u.n.spi+ISAKMP_COOKIE_LENGTH*1, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+-    pl->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_VID,
+-					     unknown_vid, sizeof (unknown_vid));
+-    pl->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_VID,
+-					     unity_vid, sizeof (unity_vid));
+-    flatten_isakmp_packet (p2, &p2kt, &p2kt_len, d->ivlen);
+-    free_isakmp_packet (p2);
+-    isakmp_crypt (d, p2kt, p2kt_len, 1);
++	if (nonce_i != NULL)
++		gcry_md_write(hm, nonce_i, ni_len);
+ 
+-    d->initial_iv = xallocc(d->ivlen);
+-    memcpy (d->initial_iv, d->current_iv, d->ivlen);
+-hex_dump("initial_iv", d->initial_iv, d->ivlen);
+-    
+-    /* Now, send that packet and receive a new one.  */
+-    r_length = sendrecv (r_packet, sizeof (r_packet), 
+-			 p2kt, p2kt_len, 0);
+-    free (p2kt);
+-  }
+-DEBUG(2, printf("S4.6\n"));
+-  
+-  free(returned_hash);
++	if (nonce_r != NULL)
++		gcry_md_write(hm, nonce_r, nr_len);
++
++	if (pl != NULL) {
++		flatten_isakmp_payload(pl, &pl_flat, &pl_size);
++		gcry_md_write(hm, pl_flat, pl_size);
++		memset(pl_flat, 0, pl_size);
++		free(pl_flat);
++	}
++
++	gcry_md_final(hm);
++	memcpy(p->payload->u.hash.data, gcry_md_read(hm, 0), s->md_len);
++	gcry_md_close(hm);
++
++	flatten_isakmp_packet(p, p_flat, p_size, s->ivlen);
++	free_isakmp_packet(p);
+ }
+ 
+-static uint16_t
+-unpack_verify_phase2 (struct sa_block *s, 
+-		      uint8_t *r_packet, 
+-		      size_t r_length,
+-		      struct isakmp_packet **r_p,
+-		      const uint8_t *nonce, size_t nonce_size)
++static void sendrecv_phase2(struct sa_block *s, struct isakmp_payload *pl,
++	uint8_t exchange_type, uint32_t msgid, int sendonly, uint8_t reply_extype,
++	uint8_t ** save_p_flat, size_t * save_p_size,
++	uint8_t * nonce_i, int ni_len, uint8_t * nonce_r, int nr_len)
+ {
+-  struct isakmp_packet *r;
+-  uint16_t reject = 0;
+-  
+-  *r_p = NULL;
+-  
+-  if (r_length < ISAKMP_PAYLOAD_O 
+-      || ((r_length - ISAKMP_PAYLOAD_O) % s->ivlen
+-	  != 0))
+-    return ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
++	uint8_t *p_flat;
++	size_t p_size;
+ 
+-  isakmp_crypt (s, r_packet, r_length, 0);
+-      
+-  {
+-    r = parse_isakmp_packet (r_packet, r_length, &reject);
+-    if (reject != 0)
+-      return reject;
+-  }
+-	
+-  /* Verify the basic stuff.  */
+-  if (memcmp (r->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH) != 0
+-      || memcmp (r->r_cookie, s->r_cookie, ISAKMP_COOKIE_LENGTH) != 0)
+-    return ISAKMP_N_INVALID_COOKIE;
+-  if (r->flags != ISAKMP_FLAG_E)
+-    return ISAKMP_N_INVALID_FLAGS;
+-  
+-  {
+-    size_t sz, spos;
+-    gcry_md_hd_t hm;
+-    unsigned char *expected_hash;
+-    struct isakmp_payload *h = r->payload;
+-    
+-    if (h == NULL
+-	|| h->type != ISAKMP_PAYLOAD_HASH
+-	|| h->u.hash.length != s->md_len)
+-      return ISAKMP_N_INVALID_HASH_INFORMATION;
+-    
+-    spos = (ISAKMP_PAYLOAD_O
+-	    + (r_packet[ISAKMP_PAYLOAD_O + 2] << 8) 
+-	    + r_packet[ISAKMP_PAYLOAD_O + 3]);
+-    
+-    /* Compute the real length based on the payload lengths.  */
+-    for (sz = spos; 
+-	 r_packet[sz] != 0; 
+-	 sz += r_packet [sz+2] << 8 | r_packet[sz+3])
+-      ;
+-    sz += r_packet [sz+2] << 8 | r_packet[sz+3];
+-    
+-    gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
+-    gcry_md_setkey(hm, s->skeyid_a, s->md_len);
+-    gcry_md_write(hm, r_packet + ISAKMP_MESSAGE_ID_O, 4);
+-    if (nonce)
+-      gcry_md_write(hm, nonce, nonce_size);
+-    gcry_md_write(hm, r_packet + spos, sz - spos);
+-    gcry_md_final(hm);
+-    expected_hash = gcry_md_read(hm, 0);
+-    
+-    if(opt_debug >= 3) {
+-	    printf("hashlen: %d\n", s->md_len);
+-	    printf("u.hash.length: %d\n", h->u.hash.length);
+-	    hex_dump("expected_hash", expected_hash,  s->md_len);
+-	    hex_dump("h->u.hash.data", h->u.hash.data, s->md_len);
+-    }
+-    
+-    reject = 0;
+-    if (memcmp (h->u.hash.data, expected_hash, s->md_len) != 0)
+-      reject = ISAKMP_N_AUTHENTICATION_FAILED;
+-    gcry_md_close(hm);
+-#if 0
+-    if (reject != 0)
+-      return reject;
+-#endif
+-  }
+-  *r_p = r;
+-  return 0;
++	if ((save_p_flat == NULL) || (*save_p_flat == NULL)) {
++		phase2_authpacket(s, pl, exchange_type, msgid, &p_flat, &p_size,
++			nonce_i, ni_len, nonce_r, nr_len);
++		isakmp_crypt(s, p_flat, p_size, 1);
++	} else {
++		p_flat = *save_p_flat;
++		p_size = *save_p_size;
++	}
++
++	if (!sendonly)
++		r_length = sendrecv(r_packet, sizeof(r_packet), p_flat, p_size, reply_extype);
++	else {
++		if (sendto(sockfd, p_flat, p_size, 0,
++				dest_addr, sizeof(struct sockaddr_in)) != (int)p_size
++			&& sendonly == 1)
++			error(1, errno, "can't send packet");
++	}
++	if (save_p_flat == NULL) {
++		free(p_flat);
++	} else {
++		*save_p_flat = p_flat;
++		*save_p_size = p_size;
++	}
+ }
+ 
+-static void
+-phase2_authpacket (struct sa_block *s, struct isakmp_payload *pl,
+-		   uint8_t exchange_type, uint32_t msgid,
+-		   uint8_t **p_flat, size_t *p_size,
+-		   uint8_t *nonce_i, int ni_len, uint8_t *nonce_r, int nr_len)
++static void phase2_fatal(struct sa_block *s, const char *msg, uint16_t id)
+ {
+-  struct isakmp_packet *p;
+-  uint8_t *pl_flat;
+-  size_t pl_size;
+-  gcry_md_hd_t hm;
+-  uint8_t msgid_sent[4];
+-
+-  /* Build up the packet.  */
+-  p = new_isakmp_packet();
+-  memcpy (p->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH);
+-  memcpy (p->r_cookie, s->r_cookie, ISAKMP_COOKIE_LENGTH);
+-  p->flags = ISAKMP_FLAG_E;
+-  p->isakmp_version = ISAKMP_VERSION;
+-  p->exchange_type = exchange_type;
+-  p->message_id = msgid;
+-  p->payload = new_isakmp_payload (ISAKMP_PAYLOAD_HASH);
+-  p->payload->next = pl;
+-  p->payload->u.hash.length = s->md_len;
+-  p->payload->u.hash.data = xallocc (s->md_len);
+-  
+-  /* Set the MAC.  */
+-  gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
+-  gcry_md_setkey(hm, s->skeyid_a, s->md_len);
+-  
+-  if (pl == NULL) {
+-    DEBUG(3, printf("authing NULL package!\n"));
+-    gcry_md_write(hm, "" /* \0 */, 1);
+-  }
+-  
+-  msgid_sent[0] = msgid >> 24;
+-  msgid_sent[1] = msgid >> 16;
+-  msgid_sent[2] = msgid >> 8;
+-  msgid_sent[3] = msgid;
+-  gcry_md_write(hm, msgid_sent, sizeof (msgid_sent));
++	struct isakmp_payload *pl;
++	uint32_t msgid;
+ 
+-  if (nonce_i != NULL)
+-    gcry_md_write(hm, nonce_i, ni_len);
+-  
+-  if (nonce_r != NULL)
+-    gcry_md_write(hm, nonce_r, nr_len);
+-  
+-  if (pl != NULL) {
+-    flatten_isakmp_payload (pl, &pl_flat, &pl_size);
+-    gcry_md_write(hm, pl_flat, pl_size);
+-    memset (pl_flat, 0, pl_size);
+-    free (pl_flat);
+-  }
++	DEBUG(1, printf("\n\n---!!!!!!!!! entering phase2_fatal !!!!!!!!!---\n\n\n"));
++	gcry_randomize((uint8_t *) & msgid, sizeof(msgid), GCRY_WEAK_RANDOM);
++	pl = new_isakmp_payload(ISAKMP_PAYLOAD_N);
++	pl->u.n.doi = ISAKMP_DOI_IPSEC;
++	pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
++	pl->u.n.type = id;
++	sendrecv_phase2(s, pl, ISAKMP_EXCHANGE_INFORMATIONAL, msgid, 2, 0, 0, 0, 0, 0, 0, 0);
+ 
+-  gcry_md_final(hm);
+-  memcpy(p->payload->u.hash.data, gcry_md_read(hm, 0), s->md_len);
+-  gcry_md_close(hm);
++	gcry_randomize((uint8_t *) & msgid, sizeof(msgid), GCRY_WEAK_RANDOM);
++	pl = new_isakmp_payload(ISAKMP_PAYLOAD_D);
++	pl->u.d.doi = ISAKMP_DOI_IPSEC;
++	pl->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
++	pl->u.d.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
++	pl->u.d.num_spi = 1;
++	pl->u.d.spi = xallocc(1 * sizeof(uint8_t *));
++	pl->u.d.spi[0] = xallocc(2 * ISAKMP_COOKIE_LENGTH);
++	memcpy(pl->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 0, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++	memcpy(pl->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 1, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++	sendrecv_phase2(s, pl, ISAKMP_EXCHANGE_INFORMATIONAL, msgid, 2, 0, 0, 0, 0, 0, 0, 0);
+ 
+-  flatten_isakmp_packet (p, p_flat, p_size, s->ivlen);
+-  free_isakmp_packet (p);
++	error(1, 0, msg, isakmp_notify_to_error(id));
+ }
+ 
+-static void
+-sendrecv_phase2 (struct sa_block *s, struct isakmp_payload *pl,
+-		 uint8_t exchange_type, uint32_t msgid, int sendonly, uint8_t reply_extype,
+-		 uint8_t **save_p_flat, size_t *save_p_size,
+-		 uint8_t *nonce_i, int ni_len, uint8_t *nonce_r, int nr_len)
++static uint8_t *gen_keymat(struct sa_block *s,
++	uint8_t protocol, uint32_t spi,
++	int md_algo, int crypt_algo,
++	const uint8_t * dh_shared, size_t dh_size,
++	const uint8_t * ni_data, size_t ni_size, const uint8_t * nr_data, size_t nr_size)
+ {
+-  uint8_t *p_flat;
+-  size_t p_size;
++	gcry_md_hd_t hm;
++	uint8_t *block;
++	int i;
++	int blksz;
++	int cnt;
+ 
+-  if ((save_p_flat == NULL)||(*save_p_flat == NULL)) {
+-    phase2_authpacket (s, pl, exchange_type, msgid, &p_flat, &p_size,
+-		  nonce_i, ni_len, nonce_r, nr_len);
+-    isakmp_crypt (s, p_flat, p_size, 1);
+-  } else {
+-    p_flat = *save_p_flat;
+-    p_size = *save_p_size;
+-  }
++	int md_len = gcry_md_get_algo_dlen(md_algo);
++	int cry_len;
+ 
+-  if (! sendonly)
+-    r_length = sendrecv (r_packet, sizeof (r_packet), 
+-			 p_flat, p_size, reply_extype);
+-  else
+-    {
+-      if (sendto (sockfd, p_flat, p_size, 0,
+-		  dest_addr, sizeof (struct sockaddr_in)) != (int) p_size
+-	  && sendonly == 1)
+-	error (1, errno, "can't send packet");
+-    }
+-  if (save_p_flat == NULL) {
+-    free (p_flat);
+-  } else {
+-    *save_p_flat = p_flat;
+-    *save_p_size = p_size;
+-  }
++	gcry_cipher_algo_info(crypt_algo, GCRYCTL_GET_KEYLEN, NULL, &cry_len);
++	blksz = md_len + cry_len;
++	cnt = (blksz + s->md_len - 1) / s->md_len;
++	block = xallocc(cnt * s->md_len);
++	DEBUG(3, printf("generating %d bytes keymat (cnt=%d)\n", blksz, cnt));
++	if (cnt < 1)
++		abort();
++
++	for (i = 0; i < cnt; i++) {
++		gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++		gcry_md_setkey(hm, s->skeyid_d, s->md_len);
++		if (i != 0)
++			gcry_md_write(hm, block + (i - 1) * s->md_len, s->md_len);
++		if (dh_shared != NULL)
++			gcry_md_write(hm, dh_shared, dh_size);
++		gcry_md_write(hm, &protocol, 1);
++		gcry_md_write(hm, (uint8_t *) & spi, sizeof(spi));
++		gcry_md_write(hm, ni_data, ni_size);
++		gcry_md_write(hm, nr_data, nr_size);
++		gcry_md_final(hm);
++		memcpy(block + i * s->md_len, gcry_md_read(hm, 0), s->md_len);
++		gcry_md_close(hm);
++	}
++	return block;
+ }
+ 
+-static void
+-phase2_fatal (struct sa_block *s, const char *msg, uint16_t id)
++/* * */
++
++struct isakmp_attribute *make_transform_ike(int dh_group, int crypt, int hash, int keylen)
+ {
+-  struct isakmp_payload *pl;
+-  uint32_t msgid;
++	struct isakmp_attribute *a = NULL;
+ 
+-DEBUG(1, printf("\n\n---!!!!!!!!! entering phase2_fatal !!!!!!!!!---\n\n\n"));
+-  gcry_randomize((uint8_t *) &msgid, sizeof (msgid), GCRY_WEAK_RANDOM);
+-  pl = new_isakmp_payload (ISAKMP_PAYLOAD_N);
+-  pl->u.n.doi = ISAKMP_DOI_IPSEC;
+-  pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
+-  pl->u.n.type = id;
+-  sendrecv_phase2 (s, pl, ISAKMP_EXCHANGE_INFORMATIONAL, msgid, 2, 0,0,0,0,0,0,0);
+-  
+-  gcry_randomize((uint8_t *) &msgid, sizeof (msgid), GCRY_WEAK_RANDOM);
+-  pl = new_isakmp_payload (ISAKMP_PAYLOAD_D);
+-  pl->u.d.doi = ISAKMP_DOI_IPSEC;
+-  pl->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
+-  pl->u.d.spi_length = 2*ISAKMP_COOKIE_LENGTH;
+-  pl->u.d.num_spi = 1;
+-  pl->u.d.spi = xallocc(1 * sizeof (uint8_t *));
+-  pl->u.d.spi[0] = xallocc(2*ISAKMP_COOKIE_LENGTH);
+-  memcpy(pl->u.d.spi[0]+ISAKMP_COOKIE_LENGTH*0, s->i_cookie, ISAKMP_COOKIE_LENGTH);
+-  memcpy(pl->u.d.spi[0]+ISAKMP_COOKIE_LENGTH*1, s->r_cookie, ISAKMP_COOKIE_LENGTH);
+-  sendrecv_phase2 (s, pl, ISAKMP_EXCHANGE_INFORMATIONAL, msgid, 2, 0,0,0,0,0,0,0);
++	a = new_isakmp_attribute(IKE_ATTRIB_LIFE_DURATION, a);
++	a->af = isakmp_attr_lots;
++	a->u.lots.length = 4;
++	a->u.lots.data = xallocc(a->u.lots.length);
++	*((uint32_t *) a->u.lots.data) = htonl(2147483);
++	a = new_isakmp_attribute_16(IKE_ATTRIB_LIFE_TYPE, IKE_LIFE_TYPE_SECONDS, a);
++	a = new_isakmp_attribute_16(IKE_ATTRIB_GROUP_DESC, dh_group, a);
++	a = new_isakmp_attribute_16(IKE_ATTRIB_AUTH_METHOD, XAUTH_AUTH_XAUTHInitPreShared, a);
++	a = new_isakmp_attribute_16(IKE_ATTRIB_HASH, hash, a);
++	a = new_isakmp_attribute_16(IKE_ATTRIB_ENC, crypt, a);
++	if (keylen != 0)
++		a = new_isakmp_attribute_16(IKE_ATTRIB_KEY_LENGTH, keylen, a);
++	return a;
++}
+ 
+-  error (1, 0, msg, isakmp_notify_to_error (id));
++struct isakmp_payload *make_our_sa_ike(void)
++{
++	struct isakmp_payload *r = new_isakmp_payload(ISAKMP_PAYLOAD_SA);
++	struct isakmp_payload *t = NULL, *tn;
++	struct isakmp_attribute *a;
++	int dh_grp = get_dh_group_ike()->ike_sa_id;
++	unsigned int crypt, hash, keylen;
++	int i;
++
++	r->u.sa.doi = ISAKMP_DOI_IPSEC;
++	r->u.sa.situation = ISAKMP_IPSEC_SIT_IDENTITY_ONLY;
++	r->u.sa.proposals = new_isakmp_payload(ISAKMP_PAYLOAD_P);
++	r->u.sa.proposals->u.p.prot_id = ISAKMP_IPSEC_PROTO_ISAKMP;
++	for (crypt = 0; supp_crypt[crypt].name != NULL; crypt++) {
++		if ((supp_crypt[crypt].my_id == GCRY_CIPHER_DES) && (opt_1des == 0))
++			continue;
++		keylen = supp_crypt[crypt].keylen;
++		for (hash = 0; supp_hash[hash].name != NULL; hash++) {
++			tn = t;
++			t = new_isakmp_payload(ISAKMP_PAYLOAD_T);
++			t->u.t.id = ISAKMP_IPSEC_KEY_IKE;
++			a = make_transform_ike(dh_grp, supp_crypt[crypt].ike_sa_id,
++				supp_hash[hash].ike_sa_id, keylen);
++			t->u.t.attributes = a;
++			t->next = tn;
++		}
++	}
++	for (i = 0, tn = t; tn; tn = tn->next)
++		tn->u.t.number = i++;
++	r->u.sa.proposals->u.p.transforms = t;
++	return r;
+ }
+ 
+-static int
+-do_phase_2_xauth (struct sa_block *s)
++void do_phase_1(const char *key_id, const char *shared_key, struct sa_block *s)
+ {
+-  struct isakmp_packet *r;
+-  int loopcount;
++	unsigned char i_nonce[20];
++	struct group *dh_grp;
++	unsigned char *dh_public;
++	unsigned char *returned_hash;
++	static const uint8_t xauth_vid[] = XAUTH_VENDOR_ID;
++	static const uint8_t unity_vid[] = UNITY_VENDOR_ID;
++	static const uint8_t unknown_vid[] = UNKNOWN_VENDOR_ID;
++#if 0
++	static const uint8_t dpd_vid[] = DPD_VENDOR_ID; /* dead peer detection */
++	static const uint8_t my_vid[] = {
++		0x35, 0x53, 0x07, 0x6c, 0x4f, 0x65, 0x12, 0x68, 0x02, 0x82, 0xf2, 0x15,
++		0x8a, 0xa8, 0xa0, 0x9e
++	};
++#endif
+ 
+-DEBUG(2, printf("S5.1\n"));
+-  /* This can go around for a while.  */
+-  for (loopcount = 0;; loopcount++)
+-    {
+-      uint16_t reject;
+-      struct isakmp_payload *rp;
+-      struct isakmp_attribute *a, *ap, *reply_attr;
+-      char ntop_buf[32];
+-      int seen_answer = 0;
+-      
+-DEBUG(2, printf("S5.2\n"));
+-      reject = unpack_verify_phase2 (s, r_packet, r_length, &r, NULL, 0);
+-      if (reject == ISAKMP_N_PAYLOAD_MALFORMED)
++	struct isakmp_packet *p1;
++
++	DEBUG(2, printf("S4.1\n"));
++	gcry_randomize(s->i_cookie, ISAKMP_COOKIE_LENGTH, GCRY_STRONG_RANDOM);
++	s->do_pfs = -1;
++	if (s->i_cookie[0] == 0)
++		s->i_cookie[0] = 1;
++	hex_dump("i_cookie", s->i_cookie, ISAKMP_COOKIE_LENGTH);
++	gcry_randomize(i_nonce, sizeof(i_nonce), GCRY_STRONG_RANDOM);
++	hex_dump("i_nonce", i_nonce, sizeof(i_nonce));
++	DEBUG(2, printf("S4.2\n"));
++	/* Set up the Diffie-Hellman stuff.  */
+ 	{
+-	  r_length = sendrecv (r_packet, sizeof (r_packet), NULL, 0, 0);
+-	  continue;
++		dh_grp = group_get(get_dh_group_ike()->my_id);
++		dh_public = xallocc(dh_getlen(dh_grp));
++		dh_create_exchange(dh_grp, dh_public);
++		hex_dump("dh_public", dh_public, dh_getlen(dh_grp));
+ 	}
+-      
+-  
+-      /* check for notices */
+-      if (reject == 0 && 
+-	  r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL &&
+-	  r->payload->next != NULL &&
+-	  r->payload->next->type == ISAKMP_PAYLOAD_N)
++
++	DEBUG(2, printf("S4.3\n"));
++	/* Create the first packet.  */
+ 	{
+-	  if (r->payload->next->u.n.type == ISAKMP_N_CISCO_LOAD_BALANCE)
+-	    {
+-	      /* load balancing notice ==> restart with new gw */
+-	      if (r->payload->next->u.n.data_length != 4)
+-	        error(1, 0, "malformed loadbalance target");
+-	      memcpy(&((struct sockaddr_in *)dest_addr)->sin_addr, r->payload->next->u.n.data, 4);
+-DEBUG(2, printf("got cisco loadbalancing notice, diverting to %s\n", inet_ntoa(((struct sockaddr_in *)dest_addr)->sin_addr)));
+-	      return 1;
+-	    }
+-	  if (r->payload->next->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME)
+-	    {
+-	      /* responder liftime notice ==> ignore */
+-DEBUG(2, printf("got responder liftime notice, ignoring..\n"));
+-	      r_length = sendrecv (r_packet, sizeof (r_packet), NULL, 0, 0);
+-	      continue;
+-	    }
++		struct isakmp_payload *l;
++		uint8_t *pkt;
++		size_t pkt_len;
++
++		p1 = new_isakmp_packet();
++		memcpy(p1->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++		p1->isakmp_version = ISAKMP_VERSION;
++		p1->exchange_type = ISAKMP_EXCHANGE_AGGRESSIVE;
++		p1->payload = l = make_our_sa_ike();
++		l->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_KE, dh_public, dh_getlen(dh_grp));
++		l->next->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_NONCE,
++			i_nonce, sizeof(i_nonce));
++		l = l->next->next;
++		l->next = new_isakmp_payload(ISAKMP_PAYLOAD_ID);
++		l = l->next;
++		l->u.id.type = ISAKMP_IPSEC_ID_KEY_ID;
++		l->u.id.protocol = IPPROTO_UDP;
++		l->u.id.port = 500; /*TODO: get local port */
++		l->u.id.length = strlen(key_id);
++		l->u.id.data = xallocc(l->u.id.length);
++		memcpy(l->u.id.data, key_id, strlen(key_id));
++		l->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_VID, xauth_vid, sizeof(xauth_vid));
++		l->next->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_VID,
++			unity_vid, sizeof(unity_vid));
++#if 0
++		l->next->next->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_VID,
++			dpd_vid, sizeof(dpd_vid));
++#endif
++		flatten_isakmp_packet(p1, &pkt, &pkt_len, 0);
++
++		/* Now, send that packet and receive a new one.  */
++		r_length = sendrecv(r_packet, sizeof(r_packet), pkt, pkt_len, 0);
++		free(pkt);
+ 	}
+-  
+-DEBUG(2, printf("S5.3\n"));
+-      /* Check the transaction type is OK.  */
+-      if (reject == 0 && 
+-	  r->exchange_type != ISAKMP_EXCHANGE_MODECFG_TRANSACTION)
+-	reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
+-      
+-      /* After the hash, expect an attribute block.  */
+-      if (reject == 0
+-	  && (r->payload->next == NULL
+-	      || r->payload->next->next != NULL
+-	      || r->payload->next->type != ISAKMP_PAYLOAD_MODECFG_ATTR))
+-	reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-      
+-      if (reject == 0 &&
+-	  r->payload->next->u.modecfg.type == ISAKMP_MODECFG_CFG_SET)
+-	break;
+-      if (reject == 0
+-	  && r->payload->next->u.modecfg.type != ISAKMP_MODECFG_CFG_REQUEST)
+-	reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-      
+-      if (reject != 0)
+-	phase2_fatal (s, "expected xauth packet; rejected: %s", reject);
+-      
+-DEBUG(2, printf("S5.4\n"));
+-      a = r->payload->next->u.modecfg.attributes;
+-      /* First, print any messages, and verify that we understand the
+-	 conversation.  */
+-      for (ap = a; ap && seen_answer == 0; ap = ap->next)
+-	if (ap->type == ISAKMP_XAUTH_ATTRIB_ANSWER)
+-	  seen_answer = 1;
+-      
+-      for (ap = a; ap && reject == 0; ap = ap->next)
+-	switch (ap->type)
+-	  {
+-	  case ISAKMP_XAUTH_ATTRIB_TYPE:
+-	    if (ap->af != isakmp_attr_16 || ap->u.attr_16 != 0)
+-	      reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	    break;
+-	  case ISAKMP_XAUTH_ATTRIB_USER_NAME:
+-	  case ISAKMP_XAUTH_ATTRIB_USER_PASSWORD:
+-	  case ISAKMP_XAUTH_ATTRIB_PASSCODE:
+-	  case ISAKMP_XAUTH_ATTRIB_DOMAIN:
+-	  case ISAKMP_XAUTH_ATTRIB_ANSWER:
+-	  case ISAKMP_XAUTH_ATTRIB_CISCOEXT_VENDOR:
+-	    break;
+-	  case ISAKMP_XAUTH_ATTRIB_MESSAGE:
+-	    if (ap->af == isakmp_attr_16)
+-	      DEBUG(seen_answer ? 0 : 1, printf ("%c%c\n", ap->u.attr_16 >> 8, ap->u.attr_16));
+-	    else
+-	      DEBUG(seen_answer ? 0 : 1, printf ("%.*s%s", ap->u.lots.length, ap->u.lots.data,
+-		      ((ap->u.lots.data
+-			&& ap->u.lots.data[ap->u.lots.length - 1] != '\n')
+-		       ? "\n" : "")));
+-	    break;
+-	  default:
+-	    reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	  }
+-DEBUG(2, printf("S5.5\n"));
+-      if (reject != 0)
+-	phase2_fatal (s, "xauth packet unsupported: %s", reject);
+-      
+-      inet_ntop (dest_addr->sa_family, 
+-		 &((struct sockaddr_in *)dest_addr)->sin_addr,
+-		 ntop_buf, sizeof (ntop_buf));
+-      
+-      /* Collect data from the user.  */
+-      reply_attr = NULL;
+-      for (ap = a; ap && reject == 0; ap = ap->next)
+-	switch (ap->type)
+-	  {
+-	  case ISAKMP_XAUTH_ATTRIB_DOMAIN:
+-	    {
+-		struct isakmp_attribute *na;
+-		na = new_isakmp_attribute(ap->type, reply_attr);
+-		reply_attr = na;
+-		na->u.lots.length = strlen (config[CONFIG_DOMAIN]);
+-		if (na->u.lots.length == 0)
+-		  error (1, 0, "server requested domain, but none set (use \"Domain ...\" in config or --domain");
+-		na->u.lots.data = xallocc (na->u.lots.length);
+-		memcpy (na->u.lots.data, config[CONFIG_DOMAIN], na->u.lots.length);
+-		break;
+-	    }
+-	  case ISAKMP_XAUTH_ATTRIB_USER_NAME:
+-	    {
+-		struct isakmp_attribute *na;
+-		na = new_isakmp_attribute(ap->type, reply_attr);
+-		reply_attr = na;
+-		na->u.lots.length = strlen (config[CONFIG_XAUTH_USERNAME]);
+-		na->u.lots.data = xallocc (na->u.lots.length);
+-		memcpy (na->u.lots.data, config[CONFIG_XAUTH_USERNAME], na->u.lots.length);
+-		break;
+-	    }
+-	  case ISAKMP_XAUTH_ATTRIB_ANSWER:
+-	    {
+-	      char *line = NULL;
+-	      size_t linelen = 0;
+-	      ssize_t linesz;
+-	      struct isakmp_attribute *na;
+-	      
+-	      if ((linesz = getline (&line, &linelen, stdin)) == -1)
+-		error (1, errno, "reading user input");
+-	      if (line[linesz - 1] == '\n')
+-		linesz--;
+-	      
+-	      na = new_isakmp_attribute(ap->type, reply_attr);
+-	      reply_attr = na;
+-	      na->u.lots.length = linesz;
+-	      na->u.lots.data = line;
+-	    }
+-	    break;
+-	    
+-	  case ISAKMP_XAUTH_ATTRIB_USER_PASSWORD:
+-	  case ISAKMP_XAUTH_ATTRIB_PASSCODE:
+-	    {
+-		struct isakmp_attribute *na;
+-		na = new_isakmp_attribute(ap->type, reply_attr);
+-		reply_attr = na;
+-		na->u.lots.length = strlen (config[CONFIG_XAUTH_PASSWORD]);
+-		na->u.lots.data = xallocc (na->u.lots.length);
+-		memcpy (na->u.lots.data, config[CONFIG_XAUTH_PASSWORD], na->u.lots.length);
+-		break;
+-	    }
+-	  default:
+-	    ;
+-	  }
+-      
+-      /* Send the response.  */
+-      rp = new_isakmp_payload (ISAKMP_PAYLOAD_MODECFG_ATTR);
+-      rp->u.modecfg.type = ISAKMP_MODECFG_CFG_REPLY;
+-      rp->u.modecfg.id = r->payload->next->u.modecfg.id;
+-      rp->u.modecfg.attributes = reply_attr;
+-      sendrecv_phase2 (s, rp, ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
+-		       r->message_id, 0, 0,0,0,0,0,0,0);
+-      
+-      free_isakmp_packet (r);
+-    }
+-  
+-DEBUG(2, printf("S5.6\n"));
+-  {
+-    /* The final SET should have just one attribute.  */
+-    uint16_t reject = 0;
+-    struct isakmp_attribute *a = r->payload->next->u.modecfg.attributes;
+-    uint16_t set_result;
+-    
+-    if (a == NULL
+-	|| a->type != ISAKMP_XAUTH_ATTRIB_STATUS
+-	|| a->af != isakmp_attr_16
+-	|| a->next != NULL)
+-      {
+-	reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-	phase2_fatal (s, "xauth SET response rejected: %s", reject);
+-      }
+-    set_result = a->u.attr_16;
++	DEBUG(2, printf("S4.4\n"));
++	/* Decode the recieved packet.  */
++	{
++		struct isakmp_packet *r;
++		uint16_t reject;
++		struct isakmp_payload *rp;
++		struct isakmp_payload *nonce = NULL;
++		struct isakmp_payload *ke = NULL;
++		struct isakmp_payload *hash = NULL;
++		struct isakmp_payload *idp = NULL;
++		int seen_xauth_vid = 0;
++		unsigned char *skeyid;
++		gcry_md_hd_t skeyid_ctx;
+ 
+-    /* ACK the SET.  */
+-    r->payload->next->u.modecfg.type = ISAKMP_MODECFG_CFG_ACK;
+-    sendrecv_phase2 (s, r->payload->next, ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
+-		     r->message_id, 1, 0,0,0,0,0,0,0);
+-    r->payload->next = NULL;
+-    free_isakmp_packet (r);
++		reject = 0;
++		r = parse_isakmp_packet(r_packet, r_length, &reject);
+ 
+-    if (set_result == 0)
+-      error (2, 0, "authentication unsuccessful");
+-  }
+-DEBUG(2, printf("S5.7\n"));
+-  return 0;
+-}
++		/* Verify the correctness of the recieved packet.  */
++		if (reject == 0 && memcmp(r->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH) != 0)
++			reject = ISAKMP_N_INVALID_COOKIE;
++		if (reject == 0)
++			memcpy(s->r_cookie, r->r_cookie, ISAKMP_COOKIE_LENGTH);
++		if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_AGGRESSIVE)
++			reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
++		if (reject == 0 && r->flags != 0)
++			reject = ISAKMP_N_INVALID_FLAGS;
++		if (reject == 0 && r->message_id != 0)
++			reject = ISAKMP_N_INVALID_MESSAGE_ID;
++		if (reject != 0)
++			error(1, 0, "response was invalid [1]: %s", isakmp_notify_to_error(reject));
++		for (rp = r->payload; rp && reject == 0; rp = rp->next)
++			switch (rp->type) {
++			case ISAKMP_PAYLOAD_SA:
++				if (reject == 0 && rp->u.sa.doi != ISAKMP_DOI_IPSEC)
++					reject = ISAKMP_N_DOI_NOT_SUPPORTED;
++				if (reject == 0 &&
++					rp->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY)
++					reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
++				if (reject == 0 &&
++					(rp->u.sa.proposals == NULL
++						|| rp->u.sa.proposals->next != NULL))
++					reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++				if (reject == 0 &&
++					rp->u.sa.proposals->u.p.prot_id !=
++					ISAKMP_IPSEC_PROTO_ISAKMP)
++					reject = ISAKMP_N_INVALID_PROTOCOL_ID;
++				if (reject == 0 && rp->u.sa.proposals->u.p.spi_size != 0)
++					reject = ISAKMP_N_INVALID_SPI;
++				if (reject == 0 &&
++					(rp->u.sa.proposals->u.p.transforms == NULL
++						|| rp->u.sa.proposals->u.p.transforms->next !=
++						NULL))
++					reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++				if (reject == 0 &&
++					(rp->u.sa.proposals->u.p.transforms->u.t.id
++						!= ISAKMP_IPSEC_KEY_IKE))
++					reject = ISAKMP_N_INVALID_TRANSFORM_ID;
++				if (reject == 0) {
++					struct isakmp_attribute *a
++						=
++						rp->u.sa.proposals->u.p.transforms->u.t.attributes;
++					int seen_enc = 0, seen_hash = 0, seen_auth = 0;
++					int seen_group = 0, seen_keylen = 0;
++					for (; a && reject == 0; a = a->next)
++						switch (a->type) {
++						case IKE_ATTRIB_GROUP_DESC:
++							if (a->af == isakmp_attr_16 &&
++								a->u.attr_16 ==
++								get_dh_group_ike()->ike_sa_id)
++								seen_group = 1;
++							else
++								reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++							break;
++						case IKE_ATTRIB_AUTH_METHOD:
++							if (a->af == isakmp_attr_16 &&
++								a->u.attr_16 ==
++								XAUTH_AUTH_XAUTHInitPreShared)
++								seen_auth = 1;
++							else
++								reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++							break;
++						case IKE_ATTRIB_HASH:
++							if (a->af == isakmp_attr_16)
++								seen_hash = a->u.attr_16;
++							else
++								reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++							break;
++						case IKE_ATTRIB_ENC:
++							if (a->af == isakmp_attr_16)
++								seen_enc = a->u.attr_16;
++							else
++								reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++							break;
++						case IKE_ATTRIB_KEY_LENGTH:
++							if (a->af == isakmp_attr_16)
++								seen_keylen = a->u.attr_16;
++							else
++								reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++							break;
++						case IKE_ATTRIB_LIFE_TYPE:
++						case IKE_ATTRIB_LIFE_DURATION:
++							break;
++						default:
++							DEBUG(1, printf
++								("unknown attribute %d, arborting..\n",
++									a->type));
++							reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++							break;
++						}
++					if (!seen_group || !seen_auth || !seen_hash || !seen_enc)
++						reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+ 
+-static void
+-addenv (const void *name, const char *value)
+-{
+-	char *strbuf = NULL, *oldval;
+-	
+-	oldval = getenv(name);
+-	if (oldval != NULL) {
+-		strbuf = xallocc(strlen(oldval) + 1 + strlen(value) + 1);
+-		strcat(strbuf, oldval);
+-		strcat(strbuf, " ");
+-		strcat(strbuf, value);
++					if (get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IKE_SA, seen_hash,
++							NULL, 0) == NULL)
++						reject = ISAKMP_N_NO_PROPOSAL_CHOSEN;
++					if (get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IKE_SA, seen_enc,
++							NULL, seen_keylen) == NULL)
++						reject = ISAKMP_N_NO_PROPOSAL_CHOSEN;
++
++					if (reject == 0) {
++						s->cry_algo =
++							get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IKE_SA,
++							seen_enc, NULL, seen_keylen)->my_id;
++						s->md_algo =
++							get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IKE_SA,
++							seen_hash, NULL, 0)->my_id;
++						DEBUG(1, printf("IKE SA selected %s-%s\n",
++								get_algo(SUPP_ALGO_CRYPT,
++									SUPP_ALGO_IKE_SA, seen_enc,
++									NULL, seen_keylen)->name,
++								get_algo(SUPP_ALGO_HASH,
++									SUPP_ALGO_IKE_SA, seen_hash,
++									NULL, 0)->name));
++					}
++				}
++				break;
++
++			case ISAKMP_PAYLOAD_ID:
++				idp = rp;
++				break;
++			case ISAKMP_PAYLOAD_KE:
++				ke = rp;
++				break;
++			case ISAKMP_PAYLOAD_NONCE:
++				nonce = rp;
++				break;
++			case ISAKMP_PAYLOAD_HASH:
++				hash = rp;
++				break;
++			case ISAKMP_PAYLOAD_VID:
++				if (rp->u.vid.length == sizeof(xauth_vid)
++					&& memcmp(rp->u.vid.data, xauth_vid,
++						sizeof(xauth_vid)) == 0)
++					seen_xauth_vid = 1;
++				break;
++			default:
++				reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++				break;
++			}
++
++		if (reject == 0) {
++			s->md_len = gcry_md_get_algo_dlen(s->md_algo);
++			gcry_cipher_algo_info(s->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(s->ivlen));
++			gcry_cipher_algo_info(s->cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(s->keylen));
++		}
++
++		if (reject == 0 && (ke == NULL || ke->u.ke.length != dh_getlen(dh_grp)))
++			reject = ISAKMP_N_INVALID_KEY_INFORMATION;
++		if (reject == 0 && nonce == NULL)
++			reject = ISAKMP_N_INVALID_HASH_INFORMATION;
++		if (reject != 0)
++			error(1, 0, "response was invalid [2]: %s", isakmp_notify_to_error(reject));
++		if (reject == 0 && idp == NULL)
++			reject = ISAKMP_N_INVALID_ID_INFORMATION;
++		if (reject == 0 && (hash == NULL || hash->u.hash.length != s->md_len))
++			reject = ISAKMP_N_INVALID_HASH_INFORMATION;
++		if (reject != 0)
++			error(1, 0, "response was invalid [3]: %s", isakmp_notify_to_error(reject));
++
++		/* Generate SKEYID.  */
++		{
++			gcry_md_open(&skeyid_ctx, s->md_algo, GCRY_MD_FLAG_HMAC);
++			gcry_md_setkey(skeyid_ctx, shared_key, strlen(shared_key));
++			gcry_md_write(skeyid_ctx, i_nonce, sizeof(i_nonce));
++			gcry_md_write(skeyid_ctx, nonce->u.nonce.data, nonce->u.nonce.length);
++			gcry_md_final(skeyid_ctx);
++			skeyid = gcry_md_read(skeyid_ctx, 0);
++			hex_dump("skeyid", skeyid, s->md_len);
++		}
++
++		/* Verify the hash.  */
++		{
++			gcry_md_hd_t hm;
++			unsigned char *expected_hash;
++			uint8_t *sa_f, *idi_f, *idp_f;
++			size_t sa_size, idi_size, idp_size;
++			struct isakmp_payload *sa, *idi;
++
++			sa = p1->payload;
++			for (idi = sa; idi->type != ISAKMP_PAYLOAD_ID; idi = idi->next) ;
++			sa->next = NULL;
++			idi->next = NULL;
++			idp->next = NULL;
++			flatten_isakmp_payload(sa, &sa_f, &sa_size);
++			flatten_isakmp_payload(idi, &idi_f, &idi_size);
++			flatten_isakmp_payload(idp, &idp_f, &idp_size);
++
++			gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++			gcry_md_setkey(hm, skeyid, s->md_len);
++			gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
++			gcry_md_write(hm, dh_public, dh_getlen(dh_grp));
++			gcry_md_write(hm, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, sa_f + 4, sa_size - 4);
++			gcry_md_write(hm, idp_f + 4, idp_size - 4);
++			gcry_md_final(hm);
++			expected_hash = gcry_md_read(hm, 0);
++
++			if (memcmp(expected_hash, hash->u.hash.data, s->md_len) != 0) {
++				error(1, 0, "hash comparison failed: %s\ncheck group password!",
++					isakmp_notify_to_error(ISAKMP_N_AUTHENTICATION_FAILED));
++			}
++			gcry_md_close(hm);
++
++			gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++			gcry_md_setkey(hm, skeyid, s->md_len);
++			gcry_md_write(hm, dh_public, dh_getlen(dh_grp));
++			gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
++			gcry_md_write(hm, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, sa_f + 4, sa_size - 4);
++			gcry_md_write(hm, idi_f + 4, idi_size - 4);
++			gcry_md_final(hm);
++			returned_hash = xallocc(s->md_len);
++			memcpy(returned_hash, gcry_md_read(hm, 0), s->md_len);
++			gcry_md_close(hm);
++			hex_dump("returned_hash", returned_hash, s->md_len);
++
++			free(sa_f);
++			free(idi);
++			free(idp);
++		}
++
++		/* Determine all the SKEYID_x keys.  */
++		{
++			gcry_md_hd_t hm;
++			int i;
++			static const unsigned char c012[3] = { 0, 1, 2 };
++			unsigned char *skeyid_e;
++			unsigned char *dh_shared_secret;
++
++			/* Determine the shared secret.  */
++			dh_shared_secret = xallocc(dh_getlen(dh_grp));
++			dh_create_shared(dh_grp, dh_shared_secret, ke->u.ke.data);
++			hex_dump("dh_shared_secret", dh_shared_secret, dh_getlen(dh_grp));
++
++			gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++			gcry_md_setkey(hm, skeyid, s->md_len);
++			gcry_md_write(hm, dh_shared_secret, dh_getlen(dh_grp));
++			gcry_md_write(hm, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, c012 + 0, 1);
++			gcry_md_final(hm);
++			s->skeyid_d = xallocc(s->md_len);
++			memcpy(s->skeyid_d, gcry_md_read(hm, 0), s->md_len);
++			gcry_md_close(hm);
++			hex_dump("skeyid_d", s->skeyid_d, s->md_len);
++
++			gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++			gcry_md_setkey(hm, skeyid, s->md_len);
++			gcry_md_write(hm, s->skeyid_d, s->md_len);
++			gcry_md_write(hm, dh_shared_secret, dh_getlen(dh_grp));
++			gcry_md_write(hm, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, c012 + 1, 1);
++			gcry_md_final(hm);
++			s->skeyid_a = xallocc(s->md_len);
++			memcpy(s->skeyid_a, gcry_md_read(hm, 0), s->md_len);
++			gcry_md_close(hm);
++			hex_dump("skeyid_a", s->skeyid_a, s->md_len);
++
++			gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++			gcry_md_setkey(hm, skeyid, s->md_len);
++			gcry_md_write(hm, s->skeyid_a, s->md_len);
++			gcry_md_write(hm, dh_shared_secret, dh_getlen(dh_grp));
++			gcry_md_write(hm, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++			gcry_md_write(hm, c012 + 2, 1);
++			gcry_md_final(hm);
++			skeyid_e = xallocc(s->md_len);
++			memcpy(skeyid_e, gcry_md_read(hm, 0), s->md_len);
++			gcry_md_close(hm);
++			hex_dump("skeyid_e", skeyid_e, s->md_len);
++
++			memset(dh_shared_secret, 0, sizeof(dh_shared_secret));
++
++			/* Determine the IKE encryption key.  */
++			s->key = xallocc(s->keylen);
++
++			if (s->keylen > s->md_len) {
++				for (i = 0; i * s->md_len < s->keylen; i++) {
++					gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
++					gcry_md_setkey(hm, skeyid_e, s->md_len);
++					if (i == 0)
++						gcry_md_write(hm, "" /* &'\0' */ , 1);
++					else
++						gcry_md_write(hm, s->key + (i - 1) * s->md_len,
++							s->md_len);
++					gcry_md_final(hm);
++					memcpy(s->key + i * s->md_len, gcry_md_read(hm, 0),
++						min(s->md_len, s->keylen - i * s->md_len));
++					gcry_md_close(hm);
++				}
++			} else { /* keylen <= md_len */
++				memcpy(s->key, skeyid_e, s->keylen);
++			}
++			hex_dump("enc-key", s->key, s->keylen);
++
++			memset(skeyid_e, 0, s->md_len);
++		}
++
++		/* Determine the initial 3DES IV.  */
++		{
++			gcry_md_hd_t hm;
++
++			assert(s->ivlen < s->md_len);
++			gcry_md_open(&hm, s->md_algo, 0);
++			gcry_md_write(hm, dh_public, dh_getlen(dh_grp));
++			gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
++			gcry_md_final(hm);
++			s->current_iv = xallocc(s->ivlen);
++			memcpy(s->current_iv, gcry_md_read(hm, 0), s->ivlen);
++			gcry_md_close(hm);
++			hex_dump("current_iv", s->current_iv, s->ivlen);
++			memset(s->current_iv_msgid, 0, 4);
++		}
++
++		gcry_md_close(skeyid_ctx);
+ 	}
+-	
+-	setenv(name, strbuf ? strbuf : value, 1);
+-	
+-	if (strbuf)
+-		free(strbuf);
++
++	DEBUG(2, printf("S4.5\n"));
++	/* Send final phase 1 packet.  */
++	{
++		struct isakmp_packet *p2;
++		uint8_t *p2kt;
++		size_t p2kt_len;
++		struct isakmp_payload *pl;
++
++		p2 = new_isakmp_packet();
++		memcpy(p2->i_cookie, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++		memcpy(p2->r_cookie, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++		p2->flags = ISAKMP_FLAG_E;
++		p2->isakmp_version = ISAKMP_VERSION;
++		p2->exchange_type = ISAKMP_EXCHANGE_AGGRESSIVE;
++		p2->payload = new_isakmp_data_payload(ISAKMP_PAYLOAD_HASH,
++			returned_hash, s->md_len);
++		p2->payload->next = pl = new_isakmp_payload(ISAKMP_PAYLOAD_N);
++		pl->u.n.doi = ISAKMP_DOI_IPSEC;
++		pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
++		pl->u.n.type = ISAKMP_N_IPSEC_INITIAL_CONTACT;
++		pl->u.n.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
++		pl->u.n.spi = xallocc(2 * ISAKMP_COOKIE_LENGTH);
++		memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 0, s->i_cookie, ISAKMP_COOKIE_LENGTH);
++		memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 1, s->r_cookie, ISAKMP_COOKIE_LENGTH);
++		pl->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_VID,
++			unknown_vid, sizeof(unknown_vid));
++		pl->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_VID,
++			unity_vid, sizeof(unity_vid));
++		flatten_isakmp_packet(p2, &p2kt, &p2kt_len, s->ivlen);
++		free_isakmp_packet(p2);
++		isakmp_crypt(s, p2kt, p2kt_len, 1);
++
++		s->initial_iv = xallocc(s->ivlen);
++		memcpy(s->initial_iv, s->current_iv, s->ivlen);
++		hex_dump("initial_iv", s->initial_iv, s->ivlen);
++
++		/* Now, send that packet and receive a new one.  */
++		r_length = sendrecv(r_packet, sizeof(r_packet), p2kt, p2kt_len, 0);
++		free(p2kt);
++	}
++	DEBUG(2, printf("S4.6\n"));
++
++	free(returned_hash);
+ }
+ 
+-static void
+-addenv_ipv4 (const void *name, uint8_t *data)
++static int do_phase_2_xauth(struct sa_block *s)
+ {
+-	addenv(name, inet_ntoa(*((struct in_addr *)data)));
++	struct isakmp_packet *r;
++	int loopcount;
++
++	DEBUG(2, printf("S5.1\n"));
++	/* This can go around for a while.  */
++	for (loopcount = 0;; loopcount++) {
++		uint16_t reject;
++		struct isakmp_payload *rp;
++		struct isakmp_attribute *a, *ap, *reply_attr;
++		char ntop_buf[32];
++		int seen_answer = 0;
++
++		DEBUG(2, printf("S5.2\n"));
++		reject = unpack_verify_phase2(s, r_packet, r_length, &r, NULL, 0);
++		if (reject == ISAKMP_N_PAYLOAD_MALFORMED) {
++			r_length = sendrecv(r_packet, sizeof(r_packet), NULL, 0, 0);
++			continue;
++		}
++
++		/* check for notices */
++		if (reject == 0 &&
++			r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL &&
++			r->payload->next != NULL && r->payload->next->type == ISAKMP_PAYLOAD_N) {
++			if (r->payload->next->u.n.type == ISAKMP_N_CISCO_LOAD_BALANCE) {
++				/* load balancing notice ==> restart with new gw */
++				if (r->payload->next->u.n.data_length != 4)
++					error(1, 0, "malformed loadbalance target");
++				memcpy(&((struct sockaddr_in *)dest_addr)->sin_addr,
++					r->payload->next->u.n.data, 4);
++				DEBUG(2, printf("got cisco loadbalancing notice, diverting to %s\n",
++						inet_ntoa(((struct sockaddr_in *)dest_addr)->
++							sin_addr)));
++				return 1;
++			}
++			if (r->payload->next->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME) {
++				/* responder liftime notice ==> ignore */
++				DEBUG(2, printf("got responder liftime notice, ignoring..\n"));
++				r_length = sendrecv(r_packet, sizeof(r_packet), NULL, 0, 0);
++				continue;
++			}
++		}
++
++		DEBUG(2, printf("S5.3\n"));
++		/* Check the transaction type is OK.  */
++		if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_MODECFG_TRANSACTION)
++			reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
++
++		/* After the hash, expect an attribute block.  */
++		if (reject == 0
++			&& (r->payload->next == NULL
++				|| r->payload->next->next != NULL
++				|| r->payload->next->type != ISAKMP_PAYLOAD_MODECFG_ATTR))
++			reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++
++		if (reject == 0 && r->payload->next->u.modecfg.type == ISAKMP_MODECFG_CFG_SET)
++			break;
++		if (reject == 0 && r->payload->next->u.modecfg.type != ISAKMP_MODECFG_CFG_REQUEST)
++			reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++
++		if (reject != 0)
++			phase2_fatal(s, "expected xauth packet; rejected: %s", reject);
++
++		DEBUG(2, printf("S5.4\n"));
++		a = r->payload->next->u.modecfg.attributes;
++		/* First, print any messages, and verify that we understand the
++		 * conversation.  */
++		for (ap = a; ap && seen_answer == 0; ap = ap->next)
++			if (ap->type == ISAKMP_XAUTH_ATTRIB_ANSWER)
++				seen_answer = 1;
++
++		for (ap = a; ap && reject == 0; ap = ap->next)
++			switch (ap->type) {
++			case ISAKMP_XAUTH_ATTRIB_TYPE:
++				if (ap->af != isakmp_attr_16 || ap->u.attr_16 != 0)
++					reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++				break;
++			case ISAKMP_XAUTH_ATTRIB_USER_NAME:
++			case ISAKMP_XAUTH_ATTRIB_USER_PASSWORD:
++			case ISAKMP_XAUTH_ATTRIB_PASSCODE:
++			case ISAKMP_XAUTH_ATTRIB_DOMAIN:
++			case ISAKMP_XAUTH_ATTRIB_ANSWER:
++			case ISAKMP_XAUTH_ATTRIB_CISCOEXT_VENDOR:
++				break;
++			case ISAKMP_XAUTH_ATTRIB_MESSAGE:
++				if (opt_debug || seen_answer || config[CONFIG_XAUTH_INTERACTIVE]) {
++					if (ap->af == isakmp_attr_16)
++						printf("%c%c\n", ap->u.attr_16 >> 8, ap->u.attr_16);
++					else
++						printf("%.*s%s", ap->u.lots.length, ap->u.lots.data,
++							((ap->u.lots.data
++									&& ap->u.lots.data[ap->u.
++										lots.length - 1] !=
++									'\n')
++								? "\n" : ""));
++				}
++				break;
++			default:
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++			}
++		DEBUG(2, printf("S5.5\n"));
++		if (reject != 0)
++			phase2_fatal(s, "xauth packet unsupported: %s", reject);
++
++		inet_ntop(dest_addr->sa_family,
++			&((struct sockaddr_in *)dest_addr)->sin_addr, ntop_buf, sizeof(ntop_buf));
++
++		/* Collect data from the user.  */
++		reply_attr = NULL;
++		for (ap = a; ap && reject == 0; ap = ap->next)
++			switch (ap->type) {
++			case ISAKMP_XAUTH_ATTRIB_DOMAIN:
++				{
++					struct isakmp_attribute *na;
++					na = new_isakmp_attribute(ap->type, reply_attr);
++					reply_attr = na;
++					na->u.lots.length = strlen(config[CONFIG_DOMAIN]);
++					if (na->u.lots.length == 0)
++						error(1, 0,
++							"server requested domain, but none set (use \"Domain ...\" in config or --domain");
++					na->u.lots.data = xallocc(na->u.lots.length);
++					memcpy(na->u.lots.data, config[CONFIG_DOMAIN],
++						na->u.lots.length);
++					break;
++				}
++			case ISAKMP_XAUTH_ATTRIB_USER_NAME:
++				{
++					struct isakmp_attribute *na;
++					na = new_isakmp_attribute(ap->type, reply_attr);
++					reply_attr = na;
++					na->u.lots.length = strlen(config[CONFIG_XAUTH_USERNAME]);
++					na->u.lots.data = xallocc(na->u.lots.length);
++					memcpy(na->u.lots.data, config[CONFIG_XAUTH_USERNAME],
++						na->u.lots.length);
++					break;
++				}
++			case ISAKMP_XAUTH_ATTRIB_ANSWER:
++			case ISAKMP_XAUTH_ATTRIB_USER_PASSWORD:
++			case ISAKMP_XAUTH_ATTRIB_PASSCODE:
++				if (seen_answer || config[CONFIG_XAUTH_INTERACTIVE]) {
++					char *pass, *prompt = NULL;
++					struct isakmp_attribute *na;
++
++					asprintf(&prompt, "%s for VPN %s@%s: ",
++						(ap->type == ISAKMP_XAUTH_ATTRIB_ANSWER) ?
++						"Answer" :
++						(ap->type == ISAKMP_XAUTH_ATTRIB_USER_PASSWORD) ?
++						"Password" : "Passcode",
++						config[CONFIG_XAUTH_USERNAME], ntop_buf);
++					pass = getpass(prompt);
++					free(prompt);
++
++					na = new_isakmp_attribute(ap->type, reply_attr);
++					reply_attr = na;
++					na->u.lots.length = strlen(pass);
++					na->u.lots.data = xallocc(na->u.lots.length);
++					memcpy(na->u.lots.data, pass, na->u.lots.length);
++					memset(pass, 0, na->u.lots.length);
++				} else {
++					struct isakmp_attribute *na;
++					na = new_isakmp_attribute(ap->type, reply_attr);
++					reply_attr = na;
++					na->u.lots.length = strlen(config[CONFIG_XAUTH_PASSWORD]);
++					na->u.lots.data = xallocc(na->u.lots.length);
++					memcpy(na->u.lots.data, config[CONFIG_XAUTH_PASSWORD],
++						na->u.lots.length);
++				}
++				break;
++			default:
++				;
++			}
++
++		/* Send the response.  */
++		rp = new_isakmp_payload(ISAKMP_PAYLOAD_MODECFG_ATTR);
++		rp->u.modecfg.type = ISAKMP_MODECFG_CFG_REPLY;
++		rp->u.modecfg.id = r->payload->next->u.modecfg.id;
++		rp->u.modecfg.attributes = reply_attr;
++		sendrecv_phase2(s, rp, ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
++			r->message_id, 0, 0, 0, 0, 0, 0, 0, 0);
++
++		free_isakmp_packet(r);
++	}
++
++	DEBUG(2, printf("S5.6\n"));
++	{
++		/* The final SET should have just one attribute.  */
++		uint16_t reject = 0;
++		struct isakmp_attribute *a = r->payload->next->u.modecfg.attributes;
++		uint16_t set_result;
++
++		if (a == NULL
++			|| a->type != ISAKMP_XAUTH_ATTRIB_STATUS
++			|| a->af != isakmp_attr_16 || a->next != NULL) {
++			reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++			phase2_fatal(s, "xauth SET response rejected: %s", reject);
++		}
++		set_result = a->u.attr_16;
++
++		/* ACK the SET.  */
++		r->payload->next->u.modecfg.type = ISAKMP_MODECFG_CFG_ACK;
++		sendrecv_phase2(s, r->payload->next, ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
++			r->message_id, 1, 0, 0, 0, 0, 0, 0, 0);
++		r->payload->next = NULL;
++		free_isakmp_packet(r);
++
++		if (set_result == 0)
++			error(2, 0, "authentication unsuccessful");
++	}
++	DEBUG(2, printf("S5.7\n"));
++	return 0;
+ }
+ 
+-static void 
+-do_phase_2_config (struct sa_block *s)
++static void do_phase_2_config(struct sa_block *s)
+ {
+-  struct isakmp_payload *rp;
+-  struct isakmp_attribute *a;
+-  struct isakmp_packet *r;
+-  struct utsname uts;
+-  uint32_t msgid;
+-  uint16_t reject;
+-  int seen_address = 0;
+-  char *strbuf;
+-  
+-  uname(&uts);
+-  
+-  gcry_randomize((uint8_t *)&msgid, sizeof (msgid), GCRY_WEAK_RANDOM);
+-  if (msgid == 0)
+-    msgid = 1;
+-  
+-  rp = new_isakmp_payload (ISAKMP_PAYLOAD_MODECFG_ATTR);
+-  rp->u.modecfg.type = ISAKMP_MODECFG_CFG_REQUEST;
+-  rp->u.modecfg.id = 20;
+-  a = NULL;
+-  
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_APPLICATION_VERSION, a);
+-  a->u.lots.length = strlen(config[CONFIG_VERSION]);
+-  a->u.lots.data = xallocc(a->u.lots.length);
+-  memcpy(a->u.lots.data, config[CONFIG_VERSION], a->u.lots.length);
+-  
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_DDNS_HOSTNAME, a);
+-  a->u.lots.length = strlen(uts.nodename);
+-  a->u.lots.data = xallocc(a->u.lots.length);
+-  memcpy(a->u.lots.data, uts.nodename, a->u.lots.length);
+-  
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_BANNER, a);
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_DO_PFS, a);
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_DEF_DOMAIN, a);
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NBNS, a);
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DNS, a);
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NETMASK, a);
+-  a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_ADDRESS, a);
+-  
+-  rp->u.modecfg.attributes = a;
+-  sendrecv_phase2 (s, rp, ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
+-		   msgid, 0, 0,0,0,0,0,0,0);
++	struct isakmp_payload *rp;
++	struct isakmp_attribute *a;
++	struct isakmp_packet *r;
++	struct utsname uts;
++	uint32_t msgid;
++	uint16_t reject;
++	int seen_address = 0;
++	char *strbuf;
+ 
+-  reject = unpack_verify_phase2 (s, r_packet, r_length, &r, NULL, 0);
++	uname(&uts);
+ 
+-  /* Check the transaction type & message ID are OK.  */
+-  if (reject == 0 && r->message_id != msgid)
+-    reject = ISAKMP_N_INVALID_MESSAGE_ID;
+-  if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_MODECFG_TRANSACTION)
+-    reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
+-  
+-  /* After the hash, expect an attribute block.  */
+-  if (reject == 0
+-      && (r->payload->next == NULL
+-	  || r->payload->next->next != NULL
+-	  || r->payload->next->type != ISAKMP_PAYLOAD_MODECFG_ATTR
++	gcry_randomize((uint8_t *) & msgid, sizeof(msgid), GCRY_WEAK_RANDOM);
++	if (msgid == 0)
++		msgid = 1;
++
++	rp = new_isakmp_payload(ISAKMP_PAYLOAD_MODECFG_ATTR);
++	rp->u.modecfg.type = ISAKMP_MODECFG_CFG_REQUEST;
++	rp->u.modecfg.id = 20;
++	a = NULL;
++
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_APPLICATION_VERSION, a);
++	a->u.lots.length = strlen(config[CONFIG_VERSION]);
++	a->u.lots.data = xallocc(a->u.lots.length);
++	memcpy(a->u.lots.data, config[CONFIG_VERSION], a->u.lots.length);
++
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_DDNS_HOSTNAME, a);
++	a->u.lots.length = strlen(uts.nodename);
++	a->u.lots.data = xallocc(a->u.lots.length);
++	memcpy(a->u.lots.data, uts.nodename, a->u.lots.length);
++
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_BANNER, a);
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_DO_PFS, a);
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_CISCO_DEF_DOMAIN, a);
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NBNS, a);
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DNS, a);
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NETMASK, a);
++	a = new_isakmp_attribute(ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_ADDRESS, a);
++
++	rp->u.modecfg.attributes = a;
++	sendrecv_phase2(s, rp, ISAKMP_EXCHANGE_MODECFG_TRANSACTION, msgid, 0, 0, 0, 0, 0, 0, 0, 0);
++
++	reject = unpack_verify_phase2(s, r_packet, r_length, &r, NULL, 0);
++
++	/* Check the transaction type & message ID are OK.  */
++	if (reject == 0 && r->message_id != msgid)
++		reject = ISAKMP_N_INVALID_MESSAGE_ID;
++	if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_MODECFG_TRANSACTION)
++		reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
++
++	/* After the hash, expect an attribute block.  */
++	if (reject == 0
++		&& (r->payload->next == NULL
++			|| r->payload->next->next != NULL
++			|| r->payload->next->type != ISAKMP_PAYLOAD_MODECFG_ATTR
+ #if 0
+-	  || r->payload->next->u.modecfg.id != 20
++			|| r->payload->next->u.modecfg.id != 20
+ #endif
+-	  || r->payload->next->u.modecfg.type != ISAKMP_MODECFG_CFG_REPLY))
+-    reject = ISAKMP_N_PAYLOAD_MALFORMED;
++			|| r->payload->next->u.modecfg.type != ISAKMP_MODECFG_CFG_REPLY))
++		reject = ISAKMP_N_PAYLOAD_MALFORMED;
+ 
+-  if (reject != 0)
+-    phase2_fatal (s, "configuration response rejected: %s", reject);
++	if (reject != 0)
++		phase2_fatal(s, "configuration response rejected: %s", reject);
+ 
+-  unsetenv("CISCO_BANNER");
+-  unsetenv("CISCO_DEF_DOMAIN");
+-  unsetenv("INTERNAL_IP4_NBNS");
+-  unsetenv("INTERNAL_IP4_DNS");
+-  unsetenv("INTERNAL_IP4_NETMASK");
+-  unsetenv("INTERNAL_IP4_ADDRESS");
+-  
+-  for (a = r->payload->next->u.modecfg.attributes; 
+-       a && reject == 0; 
+-       a = a->next)
+-    switch (a->type)
+-      {
+-      case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_ADDRESS:
+-	if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	else {
+-	  addenv_ipv4 ("INTERNAL_IP4_ADDRESS", a->u.lots.data);
+-	  memcpy(s->our_address, a->u.lots.data, 4);
+-	}
+-	seen_address = 1;
+-	break;
++	unsetenv("CISCO_BANNER");
++	unsetenv("CISCO_DEF_DOMAIN");
++	unsetenv("INTERNAL_IP4_NBNS");
++	unsetenv("INTERNAL_IP4_DNS");
++	unsetenv("INTERNAL_IP4_NETMASK");
++	unsetenv("INTERNAL_IP4_ADDRESS");
+ 
+-      case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NETMASK:
+-	if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	else
+-	  addenv_ipv4 ("INTERNAL_IP4_NETMASK", a->u.lots.data);
+-	break;
++	for (a = r->payload->next->u.modecfg.attributes; a && reject == 0; a = a->next)
++		switch (a->type) {
++		case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_ADDRESS:
++			if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++			else {
++				addenv_ipv4("INTERNAL_IP4_ADDRESS", a->u.lots.data);
++				memcpy(s->our_address, a->u.lots.data, 4);
++			}
++			seen_address = 1;
++			break;
+ 
+-      case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DNS:
+-	if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	else
+-	  addenv_ipv4 ("INTERNAL_IP4_DNS", a->u.lots.data);
+-	break;
++		case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NETMASK:
++			if (a->af == isakmp_attr_lots && a->u.lots.length == 0) {
++				DEBUG(2, printf("ignoring zero length netmask\n"));
++				continue;
++			}
++			if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++			else
++				addenv_ipv4("INTERNAL_IP4_NETMASK", a->u.lots.data);
++			break;
+ 
+-      case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NBNS:
+-	if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	else
+-	  addenv_ipv4 ("INTERNAL_IP4_NBNS", a->u.lots.data);
+-	break;
++		case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_DNS:
++			if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++			else
++				addenv_ipv4("INTERNAL_IP4_DNS", a->u.lots.data);
++			break;
+ 
+-      case ISAKMP_MODECFG_ATTRIB_CISCO_DEF_DOMAIN:
+-	if (a->af != isakmp_attr_lots) {
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	  break;
+-	}
+-	strbuf = xallocc(a->u.lots.length+1);
+-	memcpy(strbuf, a->u.lots.data, a->u.lots.length);
+-	addenv("CISCO_DEF_DOMAIN", strbuf);
+-	free(strbuf);
+-	break;
+-	
+-      case ISAKMP_MODECFG_ATTRIB_CISCO_BANNER:
+-	if (a->af != isakmp_attr_lots) {
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	  break;
+-	}
+-	strbuf = xallocc(a->u.lots.length+1);
+-	memcpy(strbuf, a->u.lots.data, a->u.lots.length);
+-	addenv("CISCO_BANNER", strbuf);
+-	free(strbuf);
+-DEBUG(1, printf("Banner: "));
+-DEBUG(1, fwrite(a->u.lots.data, a->u.lots.length, 1, stdout));
+-DEBUG(1, printf("\n"));
+-	break;
+-	
+-      case ISAKMP_MODECFG_ATTRIB_APPLICATION_VERSION:
+-DEBUG(2, printf("Remote Application Version: "));
+-DEBUG(2, fwrite(a->u.lots.data, a->u.lots.length, 1, stdout));
+-DEBUG(2, printf("\n"));
+-	break;
++		case ISAKMP_MODECFG_ATTRIB_INTERNAL_IP4_NBNS:
++			if (a->af != isakmp_attr_lots || a->u.lots.length != 4)
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++			else
++				addenv_ipv4("INTERNAL_IP4_NBNS", a->u.lots.data);
++			break;
+ 
+-      case ISAKMP_MODECFG_ATTRIB_CISCO_DO_PFS:
+-	if (a->af != isakmp_attr_16)
+-	  reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	else {
+-	  s->do_pfs = a->u.attr_16;
+-DEBUG(2, printf("got pfs setting: %d\n", s->do_pfs));
+-	}
+-	break;
++		case ISAKMP_MODECFG_ATTRIB_CISCO_DEF_DOMAIN:
++			if (a->af != isakmp_attr_lots) {
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++				break;
++			}
++			strbuf = xallocc(a->u.lots.length + 1);
++			memcpy(strbuf, a->u.lots.data, a->u.lots.length);
++			addenv("CISCO_DEF_DOMAIN", strbuf);
++			free(strbuf);
++			break;
+ 
+-      default:
+-	reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+-	break;
+-      }
+-  
+-  if (reject == 0 && ! seen_address)
+-    reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++		case ISAKMP_MODECFG_ATTRIB_CISCO_BANNER:
++			if (a->af != isakmp_attr_lots) {
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++				break;
++			}
++			strbuf = xallocc(a->u.lots.length + 1);
++			memcpy(strbuf, a->u.lots.data, a->u.lots.length);
++			addenv("CISCO_BANNER", strbuf);
++			free(strbuf);
++			DEBUG(1, printf("Banner: "));
++			DEBUG(1, fwrite(a->u.lots.data, a->u.lots.length, 1, stdout));
++			DEBUG(1, printf("\n"));
++			break;
+ 
+-  if (reject != 0)
+-    phase2_fatal (s, "configuration response rejected: %s", reject);
++		case ISAKMP_MODECFG_ATTRIB_APPLICATION_VERSION:
++			DEBUG(2, printf("Remote Application Version: "));
++			DEBUG(2, fwrite(a->u.lots.data, a->u.lots.length, 1, stdout));
++			DEBUG(2, printf("\n"));
++			break;
+ 
+-  DEBUG(1,printf("got address %s\n", getenv("INTERNAL_IP4_ADDRESS")));
+-}
++		case ISAKMP_MODECFG_ATTRIB_CISCO_DO_PFS:
++			if (a->af != isakmp_attr_16)
++				reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++			else {
++				s->do_pfs = a->u.attr_16;
++				DEBUG(2, printf("got pfs setting: %d\n", s->do_pfs));
++			}
++			break;
+ 
+-void config_tunnel(const char *dev)
+-{
+-  setenv("TUNDEV", dev, 1);
+-  setenv("VPNGATEWAY", inet_ntoa(((struct sockaddr_in *)dest_addr)->sin_addr), 1);
+-  
+-  system(config[CONFIG_CONFIG_SCRIPT]);
+-}
++		default:
++			DEBUG(2, printf("unknown attriube %d / 0x%X\n", a->type, a->type));
++			break;
++		}
+ 
+-static uint8_t *
+-gen_keymat (struct sa_block *s,
+-	    uint8_t protocol, uint32_t spi, 
+-	    int md_algo, int crypt_algo,
+-	    const uint8_t *dh_shared, size_t dh_size,
+-	    const uint8_t *ni_data, size_t ni_size,
+-	    const uint8_t *nr_data, size_t nr_size)
+-{
+-  gcry_md_hd_t hm;
+-  uint8_t *block;
+-  int i;
+-  int blksz;
+-  int cnt;
+-  
+-  int md_len = gcry_md_get_algo_dlen(md_algo);
+-  int cry_len;
+-  
+-  gcry_cipher_algo_info(crypt_algo, GCRYCTL_GET_KEYLEN, NULL, &cry_len);
+-  blksz = md_len + cry_len;
+-  cnt = (blksz + s->md_len - 1) / s->md_len;
+-  block = xallocc (cnt * s->md_len);
+-DEBUG(3, printf("generating %d bytes keymat (cnt=%d)\n", blksz, cnt));
+-  if (cnt < 1)
+-    abort ();
++	if (reject == 0 && !seen_address)
++		reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
+ 
+-  for (i = 0; i < cnt; i++)
+-    {
+-      gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
+-      gcry_md_setkey(hm, s->skeyid_d, s->md_len);
+-      if (i != 0)
+-	gcry_md_write(hm, block + (i-1) * s->md_len, s->md_len);
+-      if (dh_shared != NULL)
+-	gcry_md_write(hm, dh_shared, dh_size);
+-      gcry_md_write(hm, &protocol, 1);
+-      gcry_md_write(hm, (uint8_t *)&spi, sizeof (spi));
+-      gcry_md_write(hm, ni_data, ni_size);
+-      gcry_md_write(hm, nr_data, nr_size);
+-      gcry_md_final(hm);
+-      memcpy(block + i * s->md_len, gcry_md_read(hm, 0), s->md_len);
+-      gcry_md_close(hm);
+-    }
+-  return block;
++	if (reject != 0)
++		phase2_fatal(s, "configuration response rejected: %s", reject);
++
++	DEBUG(1, printf("got address %s\n", getenv("INTERNAL_IP4_ADDRESS")));
+ }
+ 
+-struct isakmp_attribute *
+-make_transform_ipsec(int dh_group, int hash, int keylen)
++struct isakmp_attribute *make_transform_ipsec(int dh_group, int hash, int keylen)
+ {
+-  struct isakmp_attribute *a = NULL;
+-  
+-  a = new_isakmp_attribute (ISAKMP_IPSEC_ATTRIB_SA_LIFE_DURATION, a);
+-  a->af = isakmp_attr_lots;
+-  a->u.lots.length = 4;
+-  a->u.lots.data = xallocc(a->u.lots.length);
+-  *((uint32_t *)a->u.lots.data) = htonl(2147483);
+-  a = new_isakmp_attribute_16 (ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE, IPSEC_LIFE_SECONDS, a);
+-  
+-  if (dh_group)
+-    a = new_isakmp_attribute_16 (ISAKMP_IPSEC_ATTRIB_GROUP_DESC,
+-				 dh_group, a);
+-  a = new_isakmp_attribute_16 (ISAKMP_IPSEC_ATTRIB_AUTH_ALG, 
+-			       hash, a);
+-  a = new_isakmp_attribute_16 (ISAKMP_IPSEC_ATTRIB_ENCAP_MODE,
+-			       IPSEC_ENCAP_TUNNEL, a);
+-  if (keylen != 0)
+-    a = new_isakmp_attribute_16 (ISAKMP_IPSEC_ATTRIB_KEY_LENGTH,
+-				 keylen, a);
+-  
+-  return a;
++	struct isakmp_attribute *a = NULL;
++
++	a = new_isakmp_attribute(ISAKMP_IPSEC_ATTRIB_SA_LIFE_DURATION, a);
++	a->af = isakmp_attr_lots;
++	a->u.lots.length = 4;
++	a->u.lots.data = xallocc(a->u.lots.length);
++	*((uint32_t *) a->u.lots.data) = htonl(2147483);
++	a = new_isakmp_attribute_16(ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE, IPSEC_LIFE_SECONDS, a);
++
++	if (dh_group)
++		a = new_isakmp_attribute_16(ISAKMP_IPSEC_ATTRIB_GROUP_DESC, dh_group, a);
++	a = new_isakmp_attribute_16(ISAKMP_IPSEC_ATTRIB_AUTH_ALG, hash, a);
++	a = new_isakmp_attribute_16(ISAKMP_IPSEC_ATTRIB_ENCAP_MODE, IPSEC_ENCAP_TUNNEL, a);
++	if (keylen != 0)
++		a = new_isakmp_attribute_16(ISAKMP_IPSEC_ATTRIB_KEY_LENGTH, keylen, a);
++
++	return a;
+ }
+ 
+-struct isakmp_payload *
+-make_our_sa_ipsec (struct sa_block *s)
++struct isakmp_payload *make_our_sa_ipsec(struct sa_block *s)
+ {
+-  struct isakmp_payload *r = new_isakmp_payload (ISAKMP_PAYLOAD_SA);
+-  struct isakmp_payload *t = NULL, *tn;
+-  struct isakmp_attribute *a;
+-  int dh_grp = get_dh_group_ipsec(s->do_pfs)->ipsec_sa_id;
+-  unsigned int crypt, hash, keylen;
+-  int i;
+-  
+-  r = new_isakmp_payload (ISAKMP_PAYLOAD_SA);
+-  r->u.sa.doi = ISAKMP_DOI_IPSEC;
+-  r->u.sa.situation = ISAKMP_IPSEC_SIT_IDENTITY_ONLY;
+-  r->u.sa.proposals = new_isakmp_payload (ISAKMP_PAYLOAD_P);
+-  r->u.sa.proposals->u.p.spi_size = 4;
+-  r->u.sa.proposals->u.p.spi = xallocc (4);
+-  /* The sadb_sa_spi field is already in network order.  */
+-  memcpy (r->u.sa.proposals->u.p.spi, &s->tous_esp_spi, 4);
+-  r->u.sa.proposals->u.p.prot_id = ISAKMP_IPSEC_PROTO_IPSEC_ESP;
+-  for (crypt = 0; crypt < sizeof(supp_crypt) / sizeof(supp_crypt[0]); crypt++) {
+-    if ((supp_crypt[crypt].my_id == GCRY_CIPHER_DES)&&(opt_1des == 0))
+-      continue;
+-    keylen = supp_crypt[crypt].keylen;
+-    for (hash = 0; hash < sizeof(supp_hash) / sizeof(supp_hash[0]); hash++) {
+-      tn = t;
+-      t = new_isakmp_payload (ISAKMP_PAYLOAD_T);
+-      t->u.t.id = supp_crypt[crypt].ipsec_sa_id;
+-      a = make_transform_ipsec(dh_grp, supp_hash[hash].ipsec_sa_id, keylen);
+-      t->u.t.attributes = a;
+-      t->next = tn;
+-    }
+-  }
+-  for (i = 0, tn = t; tn; tn = tn->next)
+-      tn->u.t.number = i++;
+-  r->u.sa.proposals->u.p.transforms = t;
+-  return r;
++	struct isakmp_payload *r = new_isakmp_payload(ISAKMP_PAYLOAD_SA);
++	struct isakmp_payload *p = NULL, *pn;
++	struct isakmp_attribute *a;
++	int dh_grp = get_dh_group_ipsec(s->do_pfs)->ipsec_sa_id;
++	unsigned int crypt, hash, keylen;
++	int i;
++
++	r = new_isakmp_payload(ISAKMP_PAYLOAD_SA);
++	r->u.sa.doi = ISAKMP_DOI_IPSEC;
++	r->u.sa.situation = ISAKMP_IPSEC_SIT_IDENTITY_ONLY;
++	r->u.sa.proposals = new_isakmp_payload(ISAKMP_PAYLOAD_P);
++	r->u.sa.proposals->u.p.spi_size = 4;
++	r->u.sa.proposals->u.p.spi = xallocc(4);
++	/* The sadb_sa_spi field is already in network order.  */
++	memcpy(r->u.sa.proposals->u.p.spi, &s->tous_esp_spi, 4);
++	r->u.sa.proposals->u.p.prot_id = ISAKMP_IPSEC_PROTO_IPSEC_ESP;
++	for (crypt = 0; supp_crypt[crypt].name != NULL; crypt++) {
++		if ((supp_crypt[crypt].my_id == GCRY_CIPHER_DES) && (opt_1des == 0))
++			continue;
++		keylen = supp_crypt[crypt].keylen;
++		for (hash = 0; supp_hash[hash].name != NULL; hash++) {
++			pn = p;
++			p = new_isakmp_payload(ISAKMP_PAYLOAD_P);
++			p->u.p.spi_size = 4;
++			p->u.p.spi = xallocc(4);
++			/* The sadb_sa_spi field is already in network order.  */
++			memcpy(p->u.p.spi, &s->tous_esp_spi, 4);
++			p->u.p.prot_id = ISAKMP_IPSEC_PROTO_IPSEC_ESP;
++			p->u.p.transforms = new_isakmp_payload(ISAKMP_PAYLOAD_T);
++			p->u.p.transforms->u.t.id = supp_crypt[crypt].ipsec_sa_id;
++			a = make_transform_ipsec(dh_grp, supp_hash[hash].ipsec_sa_id, keylen);
++			p->u.p.transforms->u.t.attributes = a;
++			p->next = pn;
++		}
++	}
++	for (i = 0, pn = p; pn; pn = pn->next)
++		pn->u.p.number = i++;
++	r->u.sa.proposals = p;
++	return r;
+ }
+ 
+-static void
+-setup_link (struct sa_block *s)
++static void setup_link(struct sa_block *s)
+ {
+-  struct isakmp_payload *rp, *us, *ke = NULL, *them, *nonce_r = NULL;
+-  struct isakmp_packet *r;
+-  struct group *dh_grp = NULL;
+-  uint32_t msgid;
+-  uint16_t reject;
+-  uint8_t *p_flat = NULL, *realiv = NULL, realiv_msgid[4];
+-  size_t p_size = 0;
+-  uint8_t nonce[20], *dh_public = NULL;
+-  int ipsec_cry_algo = 0, ipsec_hash_algo = 0, i;
+-  
+-DEBUG(2, printf("S7.1\n"));
+-  /* Set up the Diffie-Hellman stuff.  */
+-  if (get_dh_group_ipsec(s->do_pfs)->my_id) {
+-    dh_grp = group_get(get_dh_group_ipsec(s->do_pfs)->my_id);
+-    DEBUG(3, printf("len = %d\n", dh_getlen (dh_grp)));
+-    dh_public = xallocc(dh_getlen (dh_grp));
+-    dh_create_exchange(dh_grp, dh_public);
+-hex_dump("dh_public", dh_public, dh_getlen (dh_grp));
+-  }
+-  
+-  gcry_randomize((uint8_t *)&s->tous_esp_spi, sizeof (s->tous_esp_spi), GCRY_WEAK_RANDOM);
+-  rp = make_our_sa_ipsec(s);
+-  gcry_randomize((uint8_t *)nonce, sizeof (nonce), GCRY_WEAK_RANDOM);
+-  rp->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_NONCE,
+-				      nonce, sizeof (nonce));
+-  
+-  us = new_isakmp_payload (ISAKMP_PAYLOAD_ID);
+-  us->u.id.type = ISAKMP_IPSEC_ID_IPV4_ADDR;
+-  us->u.id.length = 4;
+-  us->u.id.data = xallocc(4);
+-  memcpy (us->u.id.data, s->our_address, sizeof (struct in_addr));
+-  them = new_isakmp_payload (ISAKMP_PAYLOAD_ID);
+-  them->u.id.type = ISAKMP_IPSEC_ID_IPV4_ADDR_SUBNET;
+-  them->u.id.length = 8;
+-  them->u.id.data = xallocc(8);
+-  memset(them->u.id.data, 0, 8);
+-  us->next = them;
+-  
+-  if (!dh_grp) {
+-    rp->next->next = us;
+-  } else {
+-    rp->next->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_KE,
+-				       dh_public, dh_getlen (dh_grp));
+-    rp->next->next->next = us;
+-  }
++	struct isakmp_payload *rp, *us, *ke = NULL, *them, *nonce_r = NULL;
++	struct isakmp_packet *r;
++	struct group *dh_grp = NULL;
++	uint32_t msgid;
++	uint16_t reject;
++	uint8_t *p_flat = NULL, *realiv = NULL, realiv_msgid[4];
++	size_t p_size = 0;
++	uint8_t nonce[20], *dh_public = NULL;
++	int ipsec_cry_algo = 0, ipsec_hash_algo = 0, i;
+ 
+-  gcry_randomize((uint8_t *)&msgid, sizeof (&msgid), GCRY_WEAK_RANDOM);
+-  if (msgid == 0)
+-    msgid = 1;
+-  
+-DEBUG(2, printf("S7.2\n"));
+-  for (i = 0; i < 4; i++) {
+-    sendrecv_phase2 (s, rp, ISAKMP_EXCHANGE_IKE_QUICK,
+-		     msgid, 0, 0, &p_flat, &p_size, 0,0,0,0);
+-    
+-    if (realiv == NULL) {
+-      realiv = xallocc(s->ivlen);
+-      memcpy(realiv, s->current_iv, s->ivlen);
+-      memcpy(realiv_msgid, s->current_iv_msgid, 4);
+-    }
++	DEBUG(2, printf("S7.1\n"));
++	/* Set up the Diffie-Hellman stuff.  */
++	if (get_dh_group_ipsec(s->do_pfs)->my_id) {
++		dh_grp = group_get(get_dh_group_ipsec(s->do_pfs)->my_id);
++		DEBUG(3, printf("len = %d\n", dh_getlen(dh_grp)));
++		dh_public = xallocc(dh_getlen(dh_grp));
++		dh_create_exchange(dh_grp, dh_public);
++		hex_dump("dh_public", dh_public, dh_getlen(dh_grp));
++	}
+ 
+-DEBUG(2, printf("S7.3\n"));
+-    reject = unpack_verify_phase2 (s, r_packet, r_length, &r, 
+-				   nonce, sizeof (nonce));
++	gcry_randomize((uint8_t *) & s->tous_esp_spi, sizeof(s->tous_esp_spi), GCRY_WEAK_RANDOM);
++	rp = make_our_sa_ipsec(s);
++	gcry_randomize((uint8_t *) nonce, sizeof(nonce), GCRY_WEAK_RANDOM);
++	rp->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_NONCE, nonce, sizeof(nonce));
+ 
+-DEBUG(2, printf("S7.4\n"));
+-    if (((reject == 0)||(reject == ISAKMP_N_AUTHENTICATION_FAILED))
+-	&& r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL) {
+-       /* handle notifie responder-lifetime (ignore)*/
+-       /* (broken hash => ignore AUTHENTICATION_FAILED) */
+-       if (reject == 0 && r->payload->next->type != ISAKMP_PAYLOAD_N)
+-         reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-       
+-       if (reject == 0 && r->payload->next->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME) {
+-DEBUG(2, printf("ignoring responder-lifetime notify\n"));
+-	 memcpy(s->current_iv, realiv, s->ivlen);
+-	 memcpy(s->current_iv_msgid, realiv_msgid, 4);
+-	 continue;
+-       }
+-    }
+-    
+-    /* Check the transaction type & message ID are OK.  */
+-    if (reject == 0 && r->message_id != msgid)
+-      reject = ISAKMP_N_INVALID_MESSAGE_ID;
+-    
+-    if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_IKE_QUICK)
+-      reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
+-  
+-    /* The SA payload must be second.  */
+-    if (reject == 0 && r->payload->next->type != ISAKMP_PAYLOAD_SA)
+-      reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-    
+-    if (p_flat)
+-      free(p_flat);
+-    if (realiv)
+-      free(realiv);
+-    break;
+-  }
++	us = new_isakmp_payload(ISAKMP_PAYLOAD_ID);
++	us->u.id.type = ISAKMP_IPSEC_ID_IPV4_ADDR;
++	us->u.id.length = 4;
++	us->u.id.data = xallocc(4);
++	memcpy(us->u.id.data, s->our_address, sizeof(struct in_addr));
++	them = new_isakmp_payload(ISAKMP_PAYLOAD_ID);
++	them->u.id.type = ISAKMP_IPSEC_ID_IPV4_ADDR_SUBNET;
++	them->u.id.length = 8;
++	them->u.id.data = xallocc(8);
++	memset(them->u.id.data, 0, 8);
++	us->next = them;
+ 
+-DEBUG(2, printf("S7.5\n"));
+-  if (reject != 0)
+-    phase2_fatal (s, "quick mode response rejected: %s\ncheck pfs setting", reject);
++	if (!dh_grp) {
++		rp->next->next = us;
++	} else {
++		rp->next->next = new_isakmp_data_payload(ISAKMP_PAYLOAD_KE,
++			dh_public, dh_getlen(dh_grp));
++		rp->next->next->next = us;
++	}
+ 
+-DEBUG(2, printf("S7.6\n"));
+-  for (rp = r->payload->next; rp && reject == 0; rp = rp->next)
+-    switch (rp->type)
+-      {
+-      case ISAKMP_PAYLOAD_SA:
+-	if (reject == 0 && rp->u.sa.doi != ISAKMP_DOI_IPSEC)
+-	  reject = ISAKMP_N_DOI_NOT_SUPPORTED;
+-	if (reject == 0 && 
+-	    rp->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY)
+-	  reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
+-	if (reject == 0 && 
+-	    (rp->u.sa.proposals == NULL
+-	     || rp->u.sa.proposals->next != NULL))
+-	  reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	if (reject == 0 &&
+-	    rp->u.sa.proposals->u.p.prot_id != ISAKMP_IPSEC_PROTO_IPSEC_ESP)
+-	  reject = ISAKMP_N_INVALID_PROTOCOL_ID;
+-	if (reject == 0 &&
+-	    rp->u.sa.proposals->u.p.spi_size != 4)
+-	  reject = ISAKMP_N_INVALID_SPI;
+-	if (reject == 0 &&
+-	    (rp->u.sa.proposals->u.p.transforms == NULL
+-	     || rp->u.sa.proposals->u.p.transforms->next != NULL))
+-	  reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	if (reject == 0) {
+-	  struct isakmp_attribute *a 
+-	    = rp->u.sa.proposals->u.p.transforms->u.t.attributes;
+-	  int seen_enc = rp->u.sa.proposals->u.p.transforms->u.t.id;
+-	  int seen_auth = 0, seen_encap = 0, seen_group = 0, seen_keylen = 0;
++	gcry_randomize((uint8_t *) & msgid, sizeof(&msgid), GCRY_WEAK_RANDOM);
++	if (msgid == 0)
++		msgid = 1;
+ 
+-	  memcpy (&s->tothem_esp_spi, rp->u.sa.proposals->u.p.spi, 4);
++	DEBUG(2, printf("S7.2\n"));
++	for (i = 0; i < 4; i++) {
++		sendrecv_phase2(s, rp, ISAKMP_EXCHANGE_IKE_QUICK,
++			msgid, 0, 0, &p_flat, &p_size, 0, 0, 0, 0);
+ 
+-	  for (; a && reject == 0; a = a->next)
+-	    switch (a->type)
+-	      {
+-	      case ISAKMP_IPSEC_ATTRIB_AUTH_ALG:
+-		if (a->af == isakmp_attr_16)
+-		  seen_auth = a->u.attr_16;
+-		else
+-		  reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		break;
+-	      case ISAKMP_IPSEC_ATTRIB_ENCAP_MODE:
+-		if (a->af == isakmp_attr_16 &&
+-		    a->u.attr_16 == IPSEC_ENCAP_TUNNEL)
+-		  seen_encap = 1;
+-		else
+-		  reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		break;
+-	      case ISAKMP_IPSEC_ATTRIB_GROUP_DESC: 
+-		if (dh_grp &&
+-		    a->af == isakmp_attr_16 &&
+-		    a->u.attr_16 == get_dh_group_ipsec(s->do_pfs)->ipsec_sa_id)
+-		  seen_group = 1;
+-		else
+-		  reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		break;
+-	      case ISAKMP_IPSEC_ATTRIB_KEY_LENGTH: 
+-		if (a->af == isakmp_attr_16)
+-		  seen_keylen = a->u.attr_16;
+-		else
+-		  reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-		break;
+-	      case ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE:
+-	      case ISAKMP_IPSEC_ATTRIB_SA_LIFE_DURATION: 
+-		break;
+-	      default:
+-		reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++		if (realiv == NULL) {
++			realiv = xallocc(s->ivlen);
++			memcpy(realiv, s->current_iv, s->ivlen);
++			memcpy(realiv_msgid, s->current_iv_msgid, 4);
++		}
++
++		DEBUG(2, printf("S7.3\n"));
++		reject = unpack_verify_phase2(s, r_packet, r_length, &r, nonce, sizeof(nonce));
++
++		DEBUG(2, printf("S7.4\n"));
++		if (((reject == 0) || (reject == ISAKMP_N_AUTHENTICATION_FAILED))
++			&& r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL) {
++			/* handle notifie responder-lifetime (ignore) */
++			/* (broken hash => ignore AUTHENTICATION_FAILED) */
++			if (reject == 0 && r->payload->next->type != ISAKMP_PAYLOAD_N)
++				reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++
++			if (reject == 0
++				&& r->payload->next->u.n.type ==
++				ISAKMP_N_IPSEC_RESPONDER_LIFETIME) {
++				DEBUG(2, printf("ignoring responder-lifetime notify\n"));
++				memcpy(s->current_iv, realiv, s->ivlen);
++				memcpy(s->current_iv_msgid, realiv_msgid, 4);
++				continue;
++			}
++		}
++
++		/* Check the transaction type & message ID are OK.  */
++		if (reject == 0 && r->message_id != msgid)
++			reject = ISAKMP_N_INVALID_MESSAGE_ID;
++
++		if (reject == 0 && r->exchange_type != ISAKMP_EXCHANGE_IKE_QUICK)
++			reject = ISAKMP_N_INVALID_EXCHANGE_TYPE;
++
++		/* The SA payload must be second.  */
++		if (reject == 0 && r->payload->next->type != ISAKMP_PAYLOAD_SA)
++			reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++
++		if (p_flat)
++			free(p_flat);
++		if (realiv)
++			free(realiv);
+ 		break;
+-	      }
+-	  if (reject == 0 && (! seen_auth || ! seen_encap ||
+-	      (dh_grp && !seen_group)))
+-	    reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	    
+-	  if (reject == 0 && get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IPSEC_SA, seen_auth, NULL, 0) == NULL)
+-	    reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	  if (reject == 0 && get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IPSEC_SA, seen_enc, NULL, seen_keylen) == NULL)
+-	    reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+-	  
+-	  if (reject == 0) {
+-	    ipsec_cry_algo = get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IPSEC_SA,
+-		     seen_enc, NULL, seen_keylen)->my_id;
+-	    ipsec_hash_algo = get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IPSEC_SA,
+-			     seen_auth, NULL, 0)->my_id;
+-	    DEBUG(1, printf("IPSEC SA selected %s-%s\n",
+-			    get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IPSEC_SA,
+-				    seen_enc, NULL, seen_keylen)->name,
+-			    get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IPSEC_SA,
+-				    seen_auth, NULL, 0)->name));
+-	  }
+ 	}
+-	break;
+-	
+-      case ISAKMP_PAYLOAD_N:		
+-	break;
+-      case ISAKMP_PAYLOAD_ID:		
+-	break;
+-      case ISAKMP_PAYLOAD_KE:
+-	ke = rp;
+-	break;
+-      case ISAKMP_PAYLOAD_NONCE:	
+-	nonce_r = rp;
+-	break;
+ 
+-      default:
+-	reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
+-	break;
+-      }
+-  
+-  if (reject == 0 && nonce_r == NULL)
+-    reject = ISAKMP_N_INVALID_HASH_INFORMATION;
+-  if (reject == 0 && dh_grp
+-	 && (ke == NULL || ke->u.ke.length != dh_getlen (dh_grp)))
+-       reject = ISAKMP_N_INVALID_KEY_INFORMATION;
+-  if (reject != 0)
+-    phase2_fatal (s, "quick mode response rejected [2]: %s", reject);
+-  
+-  /* send final packet */
+-  sendrecv_phase2 (s, NULL, ISAKMP_EXCHANGE_IKE_QUICK,
+-                   msgid, 1, 0,0,0, nonce, sizeof (nonce),
+-		   nonce_r->u.nonce.data, nonce_r->u.nonce.length);
+-  
+-DEBUG(2, printf("S7.7\n"));
+-  /* Create the delete payload, now that we have all the information.  */
+-  {
+-    struct isakmp_payload *d_isakmp, *d_ipsec;
+-    uint32_t del_msgid;
++	DEBUG(2, printf("S7.5\n"));
++	if (reject != 0)
++		phase2_fatal(s, "quick mode response rejected: %s\ncheck pfs setting", reject);
+ 
+-    gcry_randomize((uint8_t *)&del_msgid, sizeof (del_msgid), GCRY_WEAK_RANDOM);
+-    d_isakmp = new_isakmp_payload (ISAKMP_PAYLOAD_D);
+-    d_isakmp->u.d.doi = ISAKMP_DOI_IPSEC;
+-    d_isakmp->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
+-    d_isakmp->u.d.spi_length = 2*ISAKMP_COOKIE_LENGTH;
+-    d_isakmp->u.d.num_spi = 1;
+-    d_isakmp->u.d.spi = xallocc(1 * sizeof (uint8_t *));
+-    d_isakmp->u.d.spi[0] = xallocc(2*ISAKMP_COOKIE_LENGTH);
+-    memcpy(d_isakmp->u.d.spi[0]+ISAKMP_COOKIE_LENGTH*0, s->i_cookie, ISAKMP_COOKIE_LENGTH);
+-    memcpy(d_isakmp->u.d.spi[0]+ISAKMP_COOKIE_LENGTH*1, s->r_cookie, ISAKMP_COOKIE_LENGTH);
+-    d_ipsec = new_isakmp_payload (ISAKMP_PAYLOAD_D);
+-    d_ipsec->next = d_isakmp;
+-    d_ipsec->u.d.doi = ISAKMP_DOI_IPSEC;
+-    d_ipsec->u.d.protocol = ISAKMP_IPSEC_PROTO_IPSEC_ESP;
+-    d_ipsec->u.d.spi_length = 4;
+-    d_ipsec->u.d.num_spi = 2;
+-    d_ipsec->u.d.spi = xallocc (2 * sizeof (uint8_t *));
+-    d_ipsec->u.d.spi[0] = xallocc (d_ipsec->u.d.spi_length);
+-    memcpy (d_ipsec->u.d.spi[0], &s->tous_esp_spi, 4);
+-    d_ipsec->u.d.spi[1] = xallocc (d_ipsec->u.d.spi_length);
+-    memcpy (d_ipsec->u.d.spi[1], &s->tothem_esp_spi, 4);
+-    phase2_authpacket (s, d_ipsec, ISAKMP_EXCHANGE_INFORMATIONAL,
+-		       del_msgid, &s->kill_packet, &s->kill_packet_size,
+-		       nonce, sizeof (nonce),
+-		       nonce_r->u.nonce.data, nonce_r->u.nonce.length);
+-    isakmp_crypt (s, s->kill_packet, s->kill_packet_size, 1);
+-  }
+-DEBUG(2, printf("S7.8\n"));
+-  
+-  /* Set up the interface here so it's ready when our acknowledgement
+-     arrives.  */
+-  config_tunnel (tun_name);
+-DEBUG(2, printf("S7.9\n"));
+-  {
+-    uint8_t *tous_keys, *tothem_keys;
+-    struct sockaddr_in tothem_dest;
+-    unsigned char *dh_shared_secret = NULL;
++	DEBUG(2, printf("S7.6\n"));
++	for (rp = r->payload->next; rp && reject == 0; rp = rp->next)
++		switch (rp->type) {
++		case ISAKMP_PAYLOAD_SA:
++			if (reject == 0 && rp->u.sa.doi != ISAKMP_DOI_IPSEC)
++				reject = ISAKMP_N_DOI_NOT_SUPPORTED;
++			if (reject == 0 && rp->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY)
++				reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
++			if (reject == 0 &&
++				(rp->u.sa.proposals == NULL || rp->u.sa.proposals->next != NULL))
++				reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++			if (reject == 0 &&
++				rp->u.sa.proposals->u.p.prot_id != ISAKMP_IPSEC_PROTO_IPSEC_ESP)
++				reject = ISAKMP_N_INVALID_PROTOCOL_ID;
++			if (reject == 0 && rp->u.sa.proposals->u.p.spi_size != 4)
++				reject = ISAKMP_N_INVALID_SPI;
++			if (reject == 0 &&
++				(rp->u.sa.proposals->u.p.transforms == NULL
++					|| rp->u.sa.proposals->u.p.transforms->next != NULL))
++				reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++			if (reject == 0) {
++				struct isakmp_attribute *a
++					= rp->u.sa.proposals->u.p.transforms->u.t.attributes;
++				int seen_enc = rp->u.sa.proposals->u.p.transforms->u.t.id;
++				int seen_auth = 0, seen_encap = 0, seen_group = 0, seen_keylen = 0;
+ 
+-    if (dh_grp) {
+-      /* Determine the shared secret.  */
+-      dh_shared_secret = xallocc(dh_getlen (dh_grp));
+-      dh_create_shared (dh_grp, dh_shared_secret, ke->u.ke.data);
+-hex_dump("dh_shared_secret", dh_shared_secret, dh_getlen (dh_grp));
+-    }
+-    tous_keys = gen_keymat (s, ISAKMP_IPSEC_PROTO_IPSEC_ESP, s->tous_esp_spi,
+-			    ipsec_hash_algo, ipsec_cry_algo,
+-			    dh_shared_secret, dh_grp?dh_getlen (dh_grp):0,
+-			    nonce, sizeof (nonce), 
+-			    nonce_r->u.nonce.data, nonce_r->u.nonce.length);
+-    memset (&tothem_dest, 0, sizeof (tothem_dest));
+-    tothem_dest.sin_family = AF_INET;
+-    memcpy (&tothem_dest.sin_addr, s->our_address, 4);
+-    tothem_keys = gen_keymat (s, ISAKMP_IPSEC_PROTO_IPSEC_ESP, s->tothem_esp_spi,
+-			      ipsec_hash_algo, ipsec_cry_algo,
+-			      dh_shared_secret, dh_grp?dh_getlen (dh_grp):0,
+-			      nonce, sizeof (nonce), 
+-			      nonce_r->u.nonce.data, nonce_r->u.nonce.length);
+-DEBUG(2, printf("S7.10\n"));
+-    vpnc_doit (s->tous_esp_spi, tous_keys, &tothem_dest,
+-	       s->tothem_esp_spi, tothem_keys, (struct sockaddr_in *)dest_addr,
+-	       tun_fd, ipsec_hash_algo, ipsec_cry_algo,
+-	       s->kill_packet, s->kill_packet_size, dest_addr, config[CONFIG_PID_FILE]);
+-  }
+-}
++				memcpy(&s->tothem_esp_spi, rp->u.sa.proposals->u.p.spi, 4);
+ 
+-const char *config_def_description(void)
+-{ return "default value for this option"; }
++				for (; a && reject == 0; a = a->next)
++					switch (a->type) {
++					case ISAKMP_IPSEC_ATTRIB_AUTH_ALG:
++						if (a->af == isakmp_attr_16)
++							seen_auth = a->u.attr_16;
++						else
++							reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++						break;
++					case ISAKMP_IPSEC_ATTRIB_ENCAP_MODE:
++						if (a->af == isakmp_attr_16 &&
++							a->u.attr_16 == IPSEC_ENCAP_TUNNEL)
++							seen_encap = 1;
++						else
++							reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++						break;
++					case ISAKMP_IPSEC_ATTRIB_GROUP_DESC:
++						if (dh_grp &&
++							a->af == isakmp_attr_16 &&
++							a->u.attr_16 ==
++							get_dh_group_ipsec(s->do_pfs)->ipsec_sa_id)
++							seen_group = 1;
++						else
++							reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++						break;
++					case ISAKMP_IPSEC_ATTRIB_KEY_LENGTH:
++						if (a->af == isakmp_attr_16)
++							seen_keylen = a->u.attr_16;
++						else
++							reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++						break;
++					case ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE:
++					case ISAKMP_IPSEC_ATTRIB_SA_LIFE_DURATION:
++						break;
++					default:
++						reject = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;
++						break;
++					}
++				if (reject == 0 && (!seen_auth || !seen_encap ||
++						(dh_grp && !seen_group)))
++					reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+ 
+-const char *config_def_ike_dh(void)
+-{ return "dh2"; }
++				if (reject == 0
++					&& get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IPSEC_SA, seen_auth,
++						NULL, 0) == NULL)
++					reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
++				if (reject == 0
++					&& get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IPSEC_SA, seen_enc,
++						NULL, seen_keylen) == NULL)
++					reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
+ 
+-const char *config_def_pfs(void)
+-{ return "server"; }
++				if (reject == 0) {
++					ipsec_cry_algo =
++						get_algo(SUPP_ALGO_CRYPT, SUPP_ALGO_IPSEC_SA,
++						seen_enc, NULL, seen_keylen)->my_id;
++					ipsec_hash_algo =
++						get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IPSEC_SA,
++						seen_auth, NULL, 0)->my_id;
++					DEBUG(1, printf("IPSEC SA selected %s-%s\n",
++							get_algo(SUPP_ALGO_CRYPT,
++								SUPP_ALGO_IPSEC_SA, seen_enc, NULL,
++								seen_keylen)->name,
++							get_algo(SUPP_ALGO_HASH, SUPP_ALGO_IPSEC_SA,
++								seen_auth, NULL, 0)->name));
++				}
++			}
++			break;
+ 
+-const char *config_def_local_port(void)
+-{ return "500"; }
++		case ISAKMP_PAYLOAD_N:
++			break;
++		case ISAKMP_PAYLOAD_ID:
++			break;
++		case ISAKMP_PAYLOAD_KE:
++			ke = rp;
++			break;
++		case ISAKMP_PAYLOAD_NONCE:
++			nonce_r = rp;
++			break;
+ 
+-const char *config_def_app_version(void)
+-{
+-	struct utsname uts;
+-	char *version;
+- 	
+-	uname(&uts);
+-	asprintf(&version, "Cisco Systems VPN Client %s:%s", VERSION, uts.sysname);
+-	return version;
+-}
++		default:
++			reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
++			break;
++		}
+ 
+-static const struct config_names_s {
+-  enum config_enum nm;
+-  const int needsArgument;
+-  const char *option;
+-  const char *name;
+-  const char *type;
+-  const char *desc;
+-  const char *(*get_def)(void);
+-} config_names[] = {
+-  /* Note: broken config file parser does NOT support option
+-   * names where one is a prefix of another option. Needs just a bit work to
+-   * fix the parser to care about ' ' or '\t' after the wanted
+-   * option... */
+-  { CONFIG_NONE, 0,
+-    "commandline option,",
+-    "configfile variable, ",
+-    "argument type",
+-    "description",
+-    config_def_description },
+-  { CONFIG_IPSEC_GATEWAY, 1,
+-    "--gateway",
+-    "IPSec gateway ",
+-    "<ip/hostname>",
+-    "IP/name of your IPSec gateway",
+-    NULL },
+-  { CONFIG_IPSEC_ID, 1,
+-    "--id",
+-    "IPSec ID ",
+-    "<ASCII string>",
+-    "your group name",
+-    NULL },
+-  { CONFIG_IPSEC_SECRET, 1,
+-    NULL,
+-    "IPSec secret ",
+-    "<ASCII string>",
+-    "your group password (cleartext, no support for obfuscated strings)",
+-    NULL },
+-  { CONFIG_XAUTH_USERNAME, 1,
+-    "--username",
+-    "Xauth username ",
+-    "<ASCII string>",
+-    "your username",
+-    NULL },
+-  { CONFIG_XAUTH_PASSWORD, 1,
+-    NULL,
+-    "Xauth password ",
+-    "<ASCII string>",
+-    "your password (cleartext, no support for obfuscated strings)",
+-    NULL },
+-  { CONFIG_CONFIG_SCRIPT, 1,
+-    "--script",
+-    "Config Script ",
+-    "<command>",
+-    "command is executed using system() to configure the interface,\n"
+-    "      routing and so on. Device name, IP, etc. are passed using enviroment\n"
+-    "      variables, see README. This script is executed right after ISAKMP is\n"
+-    "      done, but befor tunneling is enabled.",
+-    sysdep_config_script },
+-  { CONFIG_DOMAIN, 1,
+-    "--domain",
+-    "Domain ",
+-    "<ASCII string>",
+-    "(NT-) Domain name for authentication",
+-    NULL },
+-  { CONFIG_IKE_DH, 1,
+-    "--dh",
+-    "IKE DH Group ",
+-    "<dh1/dh2/dh5>",
+-    "name of the IKE DH Group",
+-    config_def_ike_dh },
+-  { CONFIG_IPSEC_PFS, 1,
+-    "--pfs",
+-    "Perfect Forward Secrecy ",
+-    "<nopfs/dh1/dh2/dh5/server>",
+-    "Diffie-Hellman group to use for PFS",
+-    config_def_pfs },
+-  { CONFIG_ENABLE_1DES, 0,
+-    "--enable-1des",
+-    "Enable Single DES",
+-    NULL,
+-    "enables weak single DES encryption",
+-    NULL },
+-  { CONFIG_VERSION, 1,
+-    "--application-version",
+-    "Application version ",
+-    "<ASCII string>",
+-    "Application Version to report",
+-    config_def_app_version },
+-  { CONFIG_IF_NAME, 1,
+-    "--ifname",
+-    "Interface name ",
+-    "<ASCII string>",
+-    "visible name of the TUN interface",
+-    NULL },
+-  { CONFIG_DEBUG, 1,
+-    "--debug",
+-    "Debug ",
+-    "<0/1/2/3/99>",
+-    "Show verbose debug messages",
+-    NULL },
+-  { CONFIG_ND, 0,
+-    "--no-detach",
+-    "No Detach",
+-    NULL,
+-    "Don't detach from the console after login",
+-    NULL },
+-  { CONFIG_PID_FILE, 1,
+-    "--pid-file",
+-    "Pidfile ",
+-    "<filename>",
+-    "store the pid of background process in <filename>",
+-    NULL },
+-  { CONFIG_LOCAL_PORT, 1,
+-    "--local-port",
+-    "Local Port ",
+-    "<0-65535>",
+-    "local ISAKMP port number to use (0 == use random port)",
+-    config_def_local_port },
+-  { CONFIG_NON_INTERACTIVE, 0,
+-    "--non-inter",
+-    "Noninteractive",
+-    NULL,
+-    "Don't ask anything, exit on missing options",
+-    NULL },
+-  { 0, 0, NULL, NULL, NULL, NULL, NULL }
+-};
++	if (reject == 0 && nonce_r == NULL)
++		reject = ISAKMP_N_INVALID_HASH_INFORMATION;
++	if (reject == 0 && dh_grp && (ke == NULL || ke->u.ke.length != dh_getlen(dh_grp)))
++		reject = ISAKMP_N_INVALID_KEY_INFORMATION;
++	if (reject != 0)
++		phase2_fatal(s, "quick mode response rejected [2]: %s", reject);
+ 
+-void
+-read_config_file (char *name, const char **configs, int missingok)
+-{
+-  FILE *f;
+-  char *line = NULL;
+-  ssize_t line_length = 0;
+-  int linenum = 0;
+-  
+-  f = fopen (name, "r");
+-  if (missingok && f == NULL && errno == ENOENT)
+-    return;
+-  if (f == NULL)
+-    error (1, errno, "couldn't open `%s'", name);
+-  for (;;)
+-    {
+-      ssize_t llen;
+-      int i;
+-      
+-      llen = getline (&line, &line_length, f);
+-      if (llen == -1 && feof (f))
+-	break;
+-      if (llen == -1)
+-	error (1, errno, "reading `%s'", name);
+-      if (line[llen - 1] == '\n')
+-	line[llen - 1] = 0;
+-      linenum++;
+-      for (i = 0; config_names[i].name != NULL; i++) {
+-	if (config_names[i].nm == CONFIG_NONE)
+-	  continue;
+-	if (strncasecmp (config_names[i].name, line, 
+-			 strlen (config_names[i].name)) == 0)
+-	  {
+-	    // boolean implementation, using harmles pointer targets as true
+-	    if (!config_names[i].needsArgument) {
+-	      configs[config_names[i].nm] = config_names[i].name;
+-	      break;
+-	    }
+-	    if (configs[config_names[i].nm] == NULL)
+-	      configs[config_names[i].nm] = 
+-		strdup (line + strlen (config_names[i].name));
+-	    if (configs[config_names[i].nm] == NULL)
+-	      error (1, errno, "can't allocate memory");
+-	    break;
+-	  }
+-      }
+-      if (config_names[i].name == NULL && line[0] != '#' && line[0] != 0)
+-	error(0, 0, "warning: unknown configuration directive in %s at line %d",
+-	       name, linenum);
+-    }
+-}
++	/* send final packet */
++	sendrecv_phase2(s, NULL, ISAKMP_EXCHANGE_IKE_QUICK,
++		msgid, 1, 0, 0, 0, nonce, sizeof(nonce),
++		nonce_r->u.nonce.data, nonce_r->u.nonce.length);
+ 
+-void print_usage(char *argv0)
+-{
+-	int c;
+- 	
+-	printf ("Usage: %s [--version] [--print-config] [--help] [options] [config file]\n\n",
+-		argv0);
+-	printf ("Legend:\n");
+-	for (c = 0; config_names[c].name != NULL; c++) {
+-		printf ("  %s %s\n"
+-			"  %s%s\n"
+-			"      %s\n", 
+-			(config_names[c].option == NULL ? "(configfile only option)" :
+-				 config_names[c].option),
+-			((config_names[c].type == NULL || config_names[c].option == NULL) ?
+-				 "" : config_names[c].type),
+-			config_names[c].name,
+-			(config_names[c].type == NULL ? "" : config_names[c].type),
+-			config_names[c].desc);
+-		if (config_names[c].get_def != NULL)
+-			printf("    Default: %s\n", config_names[c].get_def());
+-		printf("\n");
++	DEBUG(2, printf("S7.7\n"));
++	/* Create the delete payload, now that we have all the information.  */
++	{
++		struct isakmp_payload *d_isakmp, *d_ipsec;
++		uint32_t del_msgid;
++
++		gcry_randomize((uint8_t *) & del_msgid, sizeof(del_msgid), GCRY_WEAK_RANDOM);
++		d_isakmp = new_isakmp_payload(ISAKMP_PAYLOAD_D);
++		d_isakmp->u.d.doi = ISAKMP_DOI_IPSEC;
++		d_isakmp->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
++		d_isakmp->u.d.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
++		d_isakmp->u.d.num_spi = 1;
++		d_isakmp->u.d.spi = xallocc(1 * sizeof(uint8_t *));
++		d_isakmp->u.d.spi[0] = xallocc(2 * ISAKMP_COOKIE_LENGTH);
++		memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 0, s->i_cookie,
++			ISAKMP_COOKIE_LENGTH);
++		memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 1, s->r_cookie,
++			ISAKMP_COOKIE_LENGTH);
++		d_ipsec = new_isakmp_payload(ISAKMP_PAYLOAD_D);
++		d_ipsec->next = d_isakmp;
++		d_ipsec->u.d.doi = ISAKMP_DOI_IPSEC;
++		d_ipsec->u.d.protocol = ISAKMP_IPSEC_PROTO_IPSEC_ESP;
++		d_ipsec->u.d.spi_length = 4;
++		d_ipsec->u.d.num_spi = 2;
++		d_ipsec->u.d.spi = xallocc(2 * sizeof(uint8_t *));
++		d_ipsec->u.d.spi[0] = xallocc(d_ipsec->u.d.spi_length);
++		memcpy(d_ipsec->u.d.spi[0], &s->tous_esp_spi, 4);
++		d_ipsec->u.d.spi[1] = xallocc(d_ipsec->u.d.spi_length);
++		memcpy(d_ipsec->u.d.spi[1], &s->tothem_esp_spi, 4);
++		phase2_authpacket(s, d_ipsec, ISAKMP_EXCHANGE_INFORMATIONAL,
++			del_msgid, &s->kill_packet, &s->kill_packet_size,
++			nonce, sizeof(nonce), nonce_r->u.nonce.data, nonce_r->u.nonce.length);
++		isakmp_crypt(s, s->kill_packet, s->kill_packet_size, 1);
++	}
++	DEBUG(2, printf("S7.8\n"));
++
++	/* Set up the interface here so it's ready when our acknowledgement
++	 * arrives.  */
++	config_tunnel(s);
++	DEBUG(2, printf("S7.9\n"));
++	{
++		uint8_t *tous_keys, *tothem_keys;
++		struct sockaddr_in tothem_dest;
++		unsigned char *dh_shared_secret = NULL;
++
++		if (dh_grp) {
++			/* Determine the shared secret.  */
++			dh_shared_secret = xallocc(dh_getlen(dh_grp));
++			dh_create_shared(dh_grp, dh_shared_secret, ke->u.ke.data);
++			hex_dump("dh_shared_secret", dh_shared_secret, dh_getlen(dh_grp));
++		}
++		tous_keys = gen_keymat(s, ISAKMP_IPSEC_PROTO_IPSEC_ESP, s->tous_esp_spi,
++			ipsec_hash_algo, ipsec_cry_algo,
++			dh_shared_secret, dh_grp ? dh_getlen(dh_grp) : 0,
++			nonce, sizeof(nonce), nonce_r->u.nonce.data, nonce_r->u.nonce.length);
++		memset(&tothem_dest, 0, sizeof(tothem_dest));
++		tothem_dest.sin_family = AF_INET;
++		memcpy(&tothem_dest.sin_addr, s->our_address, 4);
++		tothem_keys = gen_keymat(s, ISAKMP_IPSEC_PROTO_IPSEC_ESP, s->tothem_esp_spi,
++			ipsec_hash_algo, ipsec_cry_algo,
++			dh_shared_secret, dh_grp ? dh_getlen(dh_grp) : 0,
++			nonce, sizeof(nonce), nonce_r->u.nonce.data, nonce_r->u.nonce.length);
++		DEBUG(2, printf("S7.10\n"));
++		vpnc_doit(s->tous_esp_spi, tous_keys, &tothem_dest,
++			s->tothem_esp_spi, tothem_keys, (struct sockaddr_in *)dest_addr,
++			s->tun_fd, ipsec_hash_algo, ipsec_cry_algo,
++			s->kill_packet, s->kill_packet_size, dest_addr, config[CONFIG_PID_FILE]);
+ 	}
+-	printf ("Report bugs to vpnc@unix-ag.uni-kl.de\n");
+ }
+ 
+ int main(int argc, char **argv)
+ {
+-  struct sa_block oursa;
+-  int i, do_load_balance;
+-  int print_config = 0;
+-  const uint8_t hex_test[] = { 0, 1, 2, 3};
+-  
+-  test_pack_unpack();
+-  gcry_check_version("1.1.12");
+-  gcry_control( GCRYCTL_INIT_SECMEM, 16384, 0 );
+-  group_init();
+-  hex_dump("hex_test", hex_test, sizeof(hex_test));
+-
+-  for (i = 1; i < argc; i++)
+-    if (argv[i][0] == '-')
+-      {
+-	int c;
+-	int known = 0;
+-
+-	for (c = 0; config_names[c].name != NULL && ! known; c++)
+-	  if (config_names[c].option != NULL && config_names[c].nm != CONFIG_NONE
+-	      && strncmp (argv[i], config_names[c].option,
+-			  strlen (config_names[c].option)) == 0)
+-	    {
+-	      char *s = NULL;
+-	      
+-	      known = 1;
+-	      if (argv[i][strlen (config_names[c].option)] == '=')
+-		s = strdup (argv[i] + strlen (config_names[c].option) + 1);
+-	      else if (argv[i][strlen (config_names[c].option)] == 0) {
+-		if (config_names[c].needsArgument) {
+-		  if (i + 1 < argc)
+-		    s = argv[++i];
+-		  else
+-		    known = 0;
+-		} else
+-		  s = argv[i]; /* no arg, fill in something */
+-	      } else
+-		known = 0;
+-	      if (known)
+-		config[config_names[c].nm] = s;
+-	    }
+-	
+-	if (! known && strcmp (argv[i], "--version") == 0)
+-	  {
+-	    unsigned int i;
+-	    
+-	    printf ("vpnc version " VERSION "\n");
+-	    printf ("Copyright (C) 2002, 2003 Geoffrey Keating, Maurice Massar\n");
+-	    printf ("%s",
+-"vpnc comes with NO WARRANTY, to the extent permitted by law.\n"
+-"You may redistribute copies of vpnc under the terms of the GNU General\n"
+-"Public License.  For more information about these matters, see the files\n"
+-		    "named COPYING.\n");
+-	    printf ("\n");
+-	    printf ("Supported DH-Groups:");
+-	    for (i = 0; i < sizeof(supp_dh_group) / sizeof(supp_dh_group[0]); i++)
+-		    printf(" %s", supp_dh_group[i].name);
+-	    printf ("\n");
+-	    printf ("Supported Hash-Methods:");
+-	    for (i = 0; i < sizeof(supp_hash) / sizeof(supp_hash[0]); i++)
+-		    printf(" %s", supp_hash[i].name);
+-	    printf ("\n");
+-	    printf ("Supported Encryptions:");
+-	    for (i = 0; i < sizeof(supp_crypt) / sizeof(supp_crypt[0]); i++)
+-		    printf(" %s", supp_crypt[i].name);
+-	    printf ("\n");
+-	    exit (0);
+-	  }
+-	if (! known && strcmp (argv[i], "--print-config") == 0)
+-	  {
+-	    print_config = 1;
+-	    known = 1;
+-	    break;
+-	  }
+-	
+-	if (! known)
+-	  {
+-	    if (strcmp(argv[i], "--help") != 0)
+-	      printf ("%s: unknown option %s\n\n", argv[0], argv[i]);
+-	    
+-	    print_usage(argv[0]),
+-	    exit(1);
+-	  }
+-      }
+-    else
+-      read_config_file (argv[i], config, 0);
+-
+-  read_config_file ("/etc/vpnc/default.conf", config, 1);
+-  read_config_file ("/etc/vpnc.conf", config, 1);
+-
+-  if (!print_config)
+-    for (i = 0; config_names[i].name != NULL; i++)
+-      if (!config[config_names[i].nm] && i != CONFIG_NONE && config_names[i].get_def != NULL)
+-        config[config_names[i].nm] = config_names[i].get_def();
++	int do_load_balance;
++	const uint8_t hex_test[] = { 0, 1, 2, 3 };
+ 
+-  opt_debug=(config[CONFIG_DEBUG]) ? atoi(config[CONFIG_DEBUG]) : 0;
+-  opt_nd=(config[CONFIG_ND]) ? 1 : 0;
+-  opt_1des=(config[CONFIG_ENABLE_1DES]) ? 1 : 0;
++	test_pack_unpack();
++	gcry_check_version("1.1.90");
++	gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
++	group_init();
++	memset(oursa, 0, sizeof(oursa));
+ 
+-  if (opt_debug >= 99) {
+-	  printf("WARNING! active debug level is >= 99, output includes username and password (hex encoded)\n");
+-	  fprintf(stderr, "WARNING! active debug level is >= 99, output includes username and password (hex encoded)\n");
+-  }
+-  
+-  for (i = 0; i < LAST_CONFIG; i++)
+-    if ((config[i] == NULL)&&(config[CONFIG_NON_INTERACTIVE] == NULL))
+-      {
+-	char *s = NULL;
+-	size_t s_len = 0;
++	do_config(argc, argv);
+ 	
+-	switch (i)
+-	  {
+-	  case CONFIG_IPSEC_GATEWAY:
+-	    printf ("Enter IPSec gateway address: ");
+-	    break;
+-	  case CONFIG_IPSEC_ID:
+-	    printf ("Enter IPSec ID for %s: ", 
+-		    config[CONFIG_IPSEC_GATEWAY]);
+-	    break;
+-	  case CONFIG_IPSEC_SECRET:
+-	    printf ("Enter IPSec secret for %s@%s: ",
+-		    config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_GATEWAY]);
+-	    break;
+-	  case CONFIG_XAUTH_USERNAME:
+-	    printf ("Enter username for %s: ", config[CONFIG_IPSEC_GATEWAY]);
+-	    break;
+-	  case CONFIG_XAUTH_PASSWORD:
+-	    printf ("Enter password for %s@%s: ",
+-		    config[CONFIG_XAUTH_USERNAME],
+-		    config[CONFIG_IPSEC_GATEWAY]);
+-	    break;
+-	  }
+-	fflush (stdout);
+-        switch (i)
+-        {
+-           case CONFIG_IPSEC_SECRET:
+-           case CONFIG_XAUTH_PASSWORD:
+-              s = strdup (getpass (""));
+-              break;
+-           case CONFIG_IPSEC_GATEWAY:
+-	   case CONFIG_IPSEC_ID:
+-	   case CONFIG_XAUTH_USERNAME:
+-              getline (&s, &s_len, stdin);
+-        }
+-	if (s != NULL && s[strlen (s) - 1] == '\n')
+-	  s[strlen (s) - 1] = 0;
+-	config[i] = s;
+-      }
+-  
+-  if (print_config)
+-    {
+-      fprintf(stderr, "vpnc.conf:\n\n");
+-      for (i = 0; config_names[i].name != NULL; i++)
+-	if (config[config_names[i].nm] != NULL)
+-	  printf ("%s%s\n", config_names[i].name, (config_names[i].needsArgument)?config[config_names[i].nm]:"");
+-      exit (0);
+-    }
++	hex_dump("hex_test", hex_test, sizeof(hex_test));
+ 
+-  if (!config[CONFIG_IPSEC_GATEWAY])
+-	error (1, 0, "missing IPSec gatway address");
+-  if (!config[CONFIG_IPSEC_ID])
+-	error (1, 0, "missing IPSec ID");
+-  if (!config[CONFIG_IPSEC_SECRET])
+-	error (1, 0, "missing IPSec secret");
+-  if (!config[CONFIG_XAUTH_USERNAME])
+-	error (1, 0, "missing Xauth username");
+-  if (!config[CONFIG_XAUTH_PASSWORD])
+-	error (1, 0, "missing Xauth password");
+-  if (get_dh_group_ike() == NULL)
+-	error (1, 0, "IKE DH Group \"%s\" unsupported\n", config[CONFIG_IKE_DH]);
+-  if (get_dh_group_ipsec(-1) == NULL)
+-	error (1, 0, "Perfect Forward Secrecy \"%s\" unsupported\n", config[CONFIG_IPSEC_PFS]);
+-  if (get_dh_group_ike()->ike_sa_id == 0)
+-	error (1, 0, "IKE DH Group must not be nopfs\n");
+-  
+-DEBUG(2, printf("S1\n"));
+-  dest_addr = init_sockaddr (config[CONFIG_IPSEC_GATEWAY], 500);
+-DEBUG(2, printf("S2\n"));
+-  sockfd = make_socket (atoi(config[CONFIG_LOCAL_PORT]));
+-DEBUG(2, printf("S3\n"));
+-  setup_tunnel();
++	DEBUG(1, printf("vpnc version " VERSION "\n"));
++	DEBUG(2, printf("S1\n"));
++	dest_addr = init_sockaddr(config[CONFIG_IPSEC_GATEWAY], 500);
++	DEBUG(2, printf("S2\n"));
++	sockfd = make_socket(atoi(config[CONFIG_LOCAL_PORT]));
++	DEBUG(2, printf("S3\n"));
++	setup_tunnel(oursa);
+ 
+-  do {
+-DEBUG(2, printf("S4\n"));
+-    memset(&oursa, '\0', sizeof(oursa));
+-    do_phase_1 (config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], &oursa);
+-DEBUG(2, printf("S5\n"));
+-    do_load_balance = do_phase_2_xauth (&oursa);
+-  } while (do_load_balance);
+-DEBUG(2, printf("S6\n"));
+-  do_phase_2_config (&oursa);
+-DEBUG(2, printf("S7\n"));
+-  setup_link (&oursa);
++	do {
++		DEBUG(2, printf("S4\n"));
++		do_phase_1(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], oursa);
++		DEBUG(2, printf("S5\n"));
++		do_load_balance = do_phase_2_xauth(oursa);
++	} while (do_load_balance);
++	DEBUG(2, printf("S6\n"));
++	do_phase_2_config(oursa);
++	DEBUG(2, printf("S7\n"));
++	setup_link(oursa);
+ 
+-  return 0;
++	return 0;
+ }
+diff -Nurd vpnc-0.2-rm+zomb.1/vpnc.h new/vpnc.h
+--- vpnc-0.2-rm+zomb.1/vpnc.h	2004-05-02 22:59:12.000000000 +0200
++++ new/vpnc.h	2004-06-10 11:19:53.000000000 +0200
+@@ -1,5 +1,5 @@
+ /* IPSec VPN client compatible with Cisco equipment.
+-   Copyright (C) 2002, 2003  Geoffrey Keating and Maurice Massar
++   Copyright (C) 2002, 2003, 2004  Geoffrey Keating and Maurice Massar
+ 
+    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
+@@ -19,12 +19,44 @@
+ #ifndef __VPNC_H__
+ #define __VPNC_H__
+ 
+-extern int opt_debug;
+-extern int opt_nd;
+-extern int tun_fd;
+-extern char tun_name[];
+-extern void hex_dump (const char *str, const void *data, size_t len);
++#include <net/if.h>
++#include "sysdep.h"
++#include "isakmp.h"
+ 
+-#define DEBUG(lvl, a) do {if (opt_debug >= (lvl)) {a;}} while (0)
++typedef struct {
++	const char *name;
++	int my_id, ike_sa_id, ipsec_sa_id;
++	int keylen;
++} supported_algo_t;
++
++struct sa_block {
++	int tun_fd;
++	char tun_name[IFNAMSIZ];
++	uint8_t i_cookie[ISAKMP_COOKIE_LENGTH];
++	uint8_t r_cookie[ISAKMP_COOKIE_LENGTH];
++	uint8_t *key;
++	int keylen;
++	uint8_t *initial_iv;
++	uint8_t *skeyid_a;
++	uint8_t *skeyid_d;
++	int cry_algo, ivlen;
++	int md_algo, md_len;
++	uint8_t current_iv_msgid[4];
++	uint8_t *current_iv;
++	uint8_t our_address[4], our_netmask[4];
++	uint32_t tous_esp_spi, tothem_esp_spi;
++	uint8_t *kill_packet;
++	size_t kill_packet_size;
++	int do_pfs;
++};
++
++extern struct sa_block oursa[];
++
++extern supported_algo_t supp_dh_group[];
++extern supported_algo_t supp_hash[];
++extern supported_algo_t supp_crypt[];
++
++extern const supported_algo_t *get_dh_group_ike(void);
++extern const supported_algo_t *get_dh_group_ipsec(int server_setting);
+ 
+ #endif
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/06_vpnc_connect.dpatch
+++ vpnc-0.2-rm+zomb.1/debian/patches/06_vpnc_connect.dpatch
@@ -0,0 +1,160 @@
+#! /bin/sh -e
+## 01_vpnc-connect.dpatch by Eduard Bloch <blade@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+if [ $# -lt 1 ]; then
+    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+    exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
+
+case "$1" in
+    -patch) patch -p1 ${patch_opts} < $0;;
+    -unpatch) patch -R -p1 ${patch_opts} < $0;;
+    *)
+        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+        exit 1;;
+esac
+
+exit 0
+
+@DPATCH@
+diff -urNad /home/inet/debian/dev/vpnc/vpnc-connect vpnc/vpnc-connect
+--- /home/inet/debian/dev/vpnc/vpnc-connect	2004-06-17 16:00:28.000000000 +0200
++++ vpnc/vpnc-connect	2004-06-17 16:00:58.000000000 +0200
+@@ -12,9 +12,67 @@
+ 	sed 's/cache//;s/metric[0-9]\+ [0-9]\+//g' | xargs echo
+ }
+ 
++`cat /proc/sys/kernel/modprobe` tun 2>/dev/null
++if [ $? != 0 ]; then
++   # all this checks fail on a self-compiled kernel 2.4, though
++	( grep -q " tun_init" /proc/k*syms || test -e /sys/class/misc/tun || grep -q CONFIG_TUN=y /boot/config-`uname -r` ) 2>/dev/null || echo -e "WARNING: failed to load the tun module\n"
++fi
++
++if [ -f "$1" ]; then
++config="$1"
++elif [ -f "/etc/vpnc/$1.conf" ]; then
++	config="/etc/vpnc/$1.conf"
++elif [ -f /etc/vpnc/default.conf ]; then
++	config=/etc/vpnc/default.conf
++elif [ -f /etc/vpnc.conf ]; then
++	config=/etc/vpnc.conf
++else 
++     cat <<ECHO 1>&2
++Usage: $0 [config]
++
++ <config> can either be an absolute path or the name
++ of a config file located in /etc/vpnc/<config>.conf
++ If no config is specified, $0 will try
++ /etc/vpnc/default.conf and /etc/vpnc.conf
++
++ECHO
++exit 1
++fi
++
++if [ "$1" ] ; then shift ; fi
++
++# fix for broken devfs in kernel 2.6.x
++if [ "`readlink /dev/net/tun`" = misc/net/tun \
++   -a ! -e /dev/net/misc/net/tun -a -e /dev/misc/net/tun ] ; then
++   ln -sf /dev/misc/net/tun /dev/net/tun
++fi
++
++# make sure tun device exists
++if [ ! -e /dev/net/tun ]; then
++	mkdir -p /dev/net
++	mknod /dev/net/tun c 10 200
++fi
++
++# usual blah, blah, if the command above still failed
++test -e /dev/net/tun || echo -e "Warning, /dev/net/tun does not exist.\nPossible reasons:\n - tun driver not available\n - device file needs to be created (howto: cd /dev; /sbin/MAKEDEV tun) "
++
++getvar () {
++	if [ $# -ne 2 ]; then
++		echo "Usage: $0 <parameter file> <variable name>" 1>&2
++		return 1
++	fi
++	sed -n 's/^'"$2"' //p' "${config}"
++	return 0
++}
++
++fix_ip_get_output () {
++	sed 's/cache//;s/metric[0-9]\+ [0-9]\+//g' | xargs echo
++}
++
+ defr=/var/run/vpnc/defaultroute
+ gateway=/var/run/vpnc/gateway
+ pid=/var/run/vpnc/pid
++dnsdev=/var/run/vpnc/dev
+ 
+ if [ -z "$VPNGATEWAY" ]; then
+ 	if [ -x "`which vpnc`" ]; then
+@@ -30,7 +88,7 @@
+ 		exit 1
+ 	fi
+ 	
+-	for i in "$gateway" "$defr" "$pid"; do
++	for i in "$gateway" "$defr" "$pid" "$dnsdev" ; do
+ 		mkdir -p $(dirname "$i")
+ 	done
+ 	
+@@ -43,18 +101,50 @@
+ 		fi
+ 	fi
+ 	
+-	exec "$VPNC" --pid-file "$pid" --script "$0" "$@" || exit 1
++	exec "$VPNC" --pid-file "$pid" --script "$0 ${config} $*" "${config}" || exit 1
+ fi
+ 
+ # started from vpnc..
+ 
++if [ "$CISCO_BANNER" ] ; then echo "$CISCO_BANNER" ; fi
++
+ ifconfig $TUNDEV inet $INTERNAL_IP4_ADDRESS \
+ 	pointopoint $INTERNAL_IP4_ADDRESS \
+ 	netmask 255.255.255.255 mtu 1412 up
++
++networks="$(getvar "${config}" "Target networks")"
++
+ ip route add $(ip route get $VPNGATEWAY | fix_ip_get_output)
+-ip route | grep '^default' | fix_ip_get_output > "$defr"
+ echo "$VPNGATEWAY" > "$gateway"
+-ip route del default
+-ip route add default dev $TUNDEV
++
++if [ -z "$networks" ]; then
++    ip route | grep '^default' | fix_ip_get_output > "$defr"
++    networks=default
++fi
++for network in $networks; do
++    ip route del $network 2>/dev/null
++    ip route add $network dev $TUNDEV
++done
++
++# Debian specific resolv.conf management
++
++if [ "$INTERNAL_IP4_DNS" ] ; then
++   if test -x /sbin/resolvconf && [ "$(getvar "${config}" "DNSUpdate")" != "no" ] ; then
++      ( 
++      if [ "$CISCO_DEF_DOMAIN" ] ; then
++         echo domain "$CISCO_DEF_DOMAIN"
++         echo search "$CISCO_DEF_DOMAIN"
++      fi
++      for ip in "$INTERNAL_IP4_DNS" ; do
++         echo nameserver $ip
++      done
++      ) | /sbin/resolvconf -a $TUNDEV
++      echo $TUNDEV > $dnsdev
++   fi
++   for ip in $INTERNAL_IP4_DNS ; do
++      ip route get $ip | grep -q "dev $TUNDEV" || ip route add $ip dev $TUNDEV
++   done
++fi
++
+ ip route flush cache
+ exit 0
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/00list
+++ vpnc-0.2-rm+zomb.1/debian/patches/00list
@@ -0,0 +1,6 @@
+01_preview_2004-06-17
+02_vpnc-disconnect
+03_vpnc.8
+04_unknowncomplaints
+05_vpnc.conf
+06_vpnc_connect
--- vpnc-0.2-rm+zomb.1.orig/debian/patches/04_unknowncomplaints.dpatch
+++ vpnc-0.2-rm+zomb.1/debian/patches/04_unknowncomplaints.dpatch
@@ -0,0 +1,37 @@
+#! /bin/sh -e
+## 04_unknowncomplaints.dpatch by Eduard Bloch <blade@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+if [ $# -lt 1 ]; then
+    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+    exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"
+
+case "$1" in
+    -patch) patch -p1 ${patch_opts} < $0;;
+    -unpatch) patch -R -p1 ${patch_opts} < $0;;
+    *)
+        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
+        exit 1;;
+esac
+
+exit 0
+
+@DPATCH@
+diff -urNad /home/inet/debian/dev/vpnc/config.c vpnc/config.c
+--- /home/inet/debian/dev/vpnc/config.c	2004-06-17 16:00:28.000000000 +0200
++++ vpnc/config.c	2004-06-17 16:14:45.000000000 +0200
+@@ -313,7 +313,7 @@
+ 				break;
+ 			}
+ 		}
+-		if (config_names[i].name == NULL && line[0] != '#' && line[0] != 0)
++		if (config_names[i].name == NULL && line[0] != '#' && line[0] != 0 && opt_debug >= 3)
+ 			error(0, 0, "warning: unknown configuration directive in %s at line %d",
+ 				name, linenum);
+ 	}
--- vpnc-0.2-rm+zomb.1.orig/debian/docs
+++ vpnc-0.2-rm+zomb.1/debian/docs
@@ -0,0 +1,2 @@
+README
+TODO
--- vpnc-0.2-rm+zomb.1.orig/debian/copyright
+++ vpnc-0.2-rm+zomb.1/debian/copyright
@@ -0,0 +1,24 @@
+This package was debianized by Eduard Bloch <blade@debian.org> on
+Mon, 27 Oct 2003 20:05:37 +0100.
+
+It was downloaded from http://www.unix-ag.uni-kl.de/~massar/vpnc/ and
+will become an official repository on alioth.debian.org soon.
+
+Upstream Authors:
+
+Geoffrey Keating <geoffk@geoffk.org> , 2002
+Maurice Massar <massar@unix-ag.uni-kl.de>, 2003
+
+Copyright:
+
+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.
+
+You can find the complete text of the GPLv2 in the file
+/usr/share/common-licenses/GPL-2 on Debian systems.
+
+The source code contains parts of the isakmpd package which are licensed
+under the BSD license, refer to /usr/share/common-license/BSD for
+details.
--- vpnc-0.2-rm+zomb.1.orig/debian/rules
+++ vpnc-0.2-rm+zomb.1/debian/rules
@@ -0,0 +1,99 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+include /usr/share/dpatch/dpatch.make
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+	INSTALL_PROGRAM += -s
+endif
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	# Add here commands to configure the package.
+
+	touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp patch
+	dh_testdir
+
+	# Add here commands to compile the package.
+	$(MAKE)
+	#/usr/bin/docbook-to-man debian/vpnc.sgml > vpnc.1
+
+	touch build-stamp
+
+clean: unpatch
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+
+	# Add here commands to clean up after the build process.
+	-$(MAKE) clean
+
+	dh_clean 
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+
+	# Add here commands to install the package into debian/vpnc.
+	cp vpnc vpnc-connect vpnc-disconnect debian/vpnc/usr/sbin/
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs ChangeLog
+	dh_installdocs
+	dh_installexamples
+	install -D -m644 vpnc.conf debian/vpnc/etc/vpnc/example.conf
+#	dh_install
+#	dh_installmenu
+#	dh_installdebconf	
+#	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+#	dh_installinit
+#	dh_installcron
+#	dh_installinfo
+	dh_installman vpnc.8
+	ln -sf vpnc.8.gz debian/vpnc/usr/share/man/man8/vpnc-connect.8.gz
+	ln -sf vpnc.8.gz debian/vpnc/usr/share/man/man8/vpnc-disconnect.8.gz
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+#	dh_perl
+#	dh_python
+#	dh_makeshlibs
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
--- vpnc-0.2-rm+zomb.1.orig/debian/README.Debian
+++ vpnc-0.2-rm+zomb.1/debian/README.Debian
@@ -0,0 +1,24 @@
+vpnc for Debian
+===============
+
+The Debian version of vpnc has few improvements compared to the
+upstream version, mainly in the daemon invocation script. The
+vpnc-connect script works with multiple "profile" files, so you can
+manage multiple configurations easily. See vpnc-connect manpage for
+details.
+
+(IN)SECURITY WARNING
+====================
+
+Following this URL:
+
+<http://www.cisco.com/warp/public/707/cisco-sn-20040415-grppass.shtml>
+
+and making simple considerations about the key exchange protocol shows
+that the methods are inherently insecure. The scrambled key does not
+really protect privacy, and there is nothing to prevent possible
+man-in-the-middle-attacks. Though IPsec is used for data transfer, XAUTH
+is not a secure way to pass the login data! Be aware of this fact when
+you enter a password!
+
+ -- Eduard Bloch -- Thu, 17 Jun 2004 15:26:01 +0200
