[prev in list] [next in list] [prev in thread] [next in thread] 

List:       ipsec-tools-devel
Subject:    Re: [Ipsec-tools-devel] Ipsec-tools-0.7 and Cisco ASA 5520
From:       "L. Gabriel Somlo" <somlo () cmu ! edu>
Date:       2008-06-25 19:04:28
Message-ID: 20080625190428.GA22515 () hedwig ! net ! cmu ! edu
[Download RAW message or body]

> Two of the three patches were committed to the head branch but are not yet
> included in a release. The third patch, a work around which prevented
> scripts from being executed more than once, was not committed. I had
> intended to do some work in IKE config mode to improve state tracking which
> would have made the patch irrelevant. Unfortunately, I never got around to
> it due to lack of time.

The third patch is unnecessary, as the phase1_up_down script can
easily perform those checks. I'm attaching my current linux and bsd
specific phase1_up_down scripts. I had a thread (with Manu, iirc)
about potentially including these in src/racoon/samples/roadwarrior/client/
but we got stuck trying to resolve whether having two scripts, one for
BSD and one for Linux was worse than having one script with a metric
ton of

case $OS in
  bsd*)
    foo
    ;;
  linux*)
    bar
    ;;
esac

So, if these scripts are accepted, the third patch Matthew mentions
becomes unecessary.

There was a later, fourth patch, which fixes the broken handling of
SADB_DELETE on Linux. I'm also re-attaching that one to this message.
Please consider applying this one to the head branch, as well.

Thanks,
Gabriel

["phase1-up-down-bsd.sh" (application/x-sh)]

#!/bin/sh

#
# manipulate IPSec SA database on behalf of the racoon daemon
# Gabriel Somlo <somlo at cmu edu>, 08/27/2007
#

#FIXME: read this from a config file
NAT_T="yes"


umask 0022

PATH=/bin:/sbin:/usr/bin:/usr/sbin

# set up NAT-T
case "${NAT_T}" in
  yes|true|on|enable*|1)
    LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]"
    REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]"
    ;;
  *)
    LOCAL="${LOCAL_ADDR}"
    REMOTE="${REMOTE_ADDR}"
    ;;
esac

# determine interface and next-hop for our default route
DFLT_RT=$(netstat -rn | awk '($1 == "default"){print $2 ";" $7}')
DFLT_IF=${DFLT_RT#*;}
DFLT_GW=${DFLT_RT%;*}


# bring up phase1
phase1_up() {
  # check if VPN address already set up on default interface (dupe script call)
  ifconfig ${DFLT_IF} | grep -q "${INTERNAL_ADDR4}" && {
    echo "p1_up_down: phase1_up has already run !!!"
    exit 4
  }

  # save current resolv.conf and create new one based on info from VPN server
  [ -f /etc/resolv.conf.prevpn ] || cp /etc/resolv.conf /etc/resolv.conf.prevpn
  {
    echo "# Generated by racoon on $(date)"
    echo "search ${DEFAULT_DOMAIN}"
    for NS in ${INTERNAL_DNS4_LIST}; do
      echo "nameserver ${NS}"
    done
  } > /etc/resolv.conf

  # add VPN address to default interface
  ifconfig ${DFLT_IF} alias ${INTERNAL_ADDR4} netmask 255.255.255.255
  # set up host route to VPN server
  route add ${REMOTE_ADDR} ${DEFAULT_GW}

  if [ -n "${SPLIT_INCLUDE}" ]; then
    # split tunnel: keep existing default, insert specific tunnel routes
    for N in ${SPLIT_INCLUDE}; do
      NETADDR=${N%/*}
      NETMASK=${N#*/}
      route add -net ${NETADDR} netmask ${NETMASK} gw ${DFLT_GW} -ifa ${INTERNAL_ADDR4}
    done
  else
    # full tunnel: set up any applicable exceptions
    for N in ${SPLIT_LOCAL}; do
      NETADDR=${N%/*}
      NETMASK=${N#*/}
      route add -net ${NETADDR} netmask ${NETMASK} gw ${DFLT_GW}
    done
    # ... then replace default route with vpn tunnel
    route delete default
    route add default gw ${DFLT_GW} -ifa ${INTERNAL_ADDR4}
  fi

  # update SA database
  setkey -c << EOT
spdadd ${INTERNAL_ADDR4}/32[any] 0.0.0.0/0[any] any -P out ipsec
       esp/tunnel/${LOCAL}-${REMOTE}/require;
spdadd 0.0.0.0/0[any] ${INTERNAL_ADDR4}[any] any -P in ipsec
       esp/tunnel/${REMOTE}-${LOCAL}/require;
EOT
}

# bring down phase1
phase1_down() {
  # restore previous resolv.conf
  [ -f /etc/resolv.conf.prevpn ] && mv /etc/resolv.conf.prevpn /etc/resolv.conf

  if [ -n "${SPLIT_INCLUDE}" ]; then
    # split tunnel: remove specific tunnel routes
    for N in ${SPLIT_INCLUDE}; do
      NETADDR=${N%/*}
      NETMASK=${N#*/}
      route del -net ${NETADDR} netmask ${NETMASK}
    done
  else
    # full tunnel: remove any applicable exceptions
    for N in ${SPLIT_LOCAL}; do
      NETADDR=${N%/*}
      NETMASK=${N#*/}
      route del -net ${NETADDR} netmask ${NETMASK}
    done
    # ... then restore original default route
    route delete default
    route add default ${DFLT_GW} -ifa ${LOCAL_ADDR}
  fi

  # remove host route to VPN server
  route delete ${REMOTE_ADDR}
  # remove VPN address from default interface
  ifconfig ${DFLT_IF} delete ${INTERNAL_ADDR4}

  # clean up SA database
  # (deleteall command may be broken on Linux, use 'flush esp' as workaround)
  setkey -c << EOT
spddelete ${INTERNAL_ADDR4}/32[any] 0.0.0.0/0[any] any -P out ipsec
          esp/tunnel/${LOCAL}-${REMOTE}/require;
spddelete 0.0.0.0/0[any] ${INTERNAL_ADDR4}[any] any -P in ipsec
          esp/tunnel/${REMOTE}-${LOCAL}/require;
deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp;
deleteall ${LOCAL_ADDR} ${REMOTE_ADDR} esp; 
EOT
}


# print out parameters we received
echo "p1_up_down: $1 starting..."
echo "p1_up_down: LOCAL_ADDR = ${LOCAL_ADDR}"
echo "p1_up_down: LOCAL_PORT = ${LOCAL_PORT}"
echo "p1_up_down: REMOTE_ADDR = ${REMOTE_ADDR}"
echo "p1_up_down: REMOTE_PORT = ${REMOTE_PORT}"
echo "p1_up_down: DFLT_GW = ${DFLT_GW}"
echo "p1_up_down: DFLT_IF = ${DFLT_IF}"
echo "p1_up_down: INTERNAL_ADDR4 = ${INTERNAL_ADDR4}"
echo "p1_up_down: INTERNAL_DNS4 = ${INTERNAL_DNS4}"
echo "p1_up_down: DEFAULT_DOMAIN = ${DEFAULT_DOMAIN}"
echo "p1_up_down: SPLIT_INCLUDE = ${SPLIT_INCLUDE}"
echo "p1_up_down: SPLIT_LOCAL= ${SPLIT_LOCAL}"

# check for valid VPN address
echo ${INTERNAL_ADDR4} | grep -q '[0-9]' || {
  echo "p1_up_down: error: invalid INTERNAL_ADDR4."
  exit 1
}

# check for valid default nexthop
echo ${DFLT_GW} | grep -q '[0-9]' || {
  echo "p1_up_down: error: invalid DFLT_GW."
  exit 2
}

# main "program"
case "$1" in
  phase1_up)
    phase1_up
    ;;
  phase1_down)
    phase1_down
    ;;
  *)
    echo "p1_up_down: error: must be called by racoon w. arg=phase1_[up|down]"
    exit 3
    ;;
esac

echo "p1_up_down: $1 completed successfully."
exit 0

["phase1-up-down-linux.sh" (application/x-sh)]

#!/bin/bash

#
# manipulate IPSec SA database on behalf of the racoon daemon
# Gabriel Somlo <somlo at cmu edu>, 08/27/2007
#

#FIXME: read this from a config file
NAT_T="yes"


umask 0022

PATH=/bin:/sbin:/usr/bin:/usr/sbin

# set up NAT-T
case "${NAT_T}" in
  yes|true|on|enable*|1)
    LOCAL="${LOCAL_ADDR}[${LOCAL_PORT}]"
    REMOTE="${REMOTE_ADDR}[${REMOTE_PORT}]"
    ;;
  *)
    LOCAL="${LOCAL_ADDR}"
    REMOTE="${REMOTE_ADDR}"
    ;;
esac

# determine interface and next-hop for our default route
DFLT_RT=$(ip route list | awk '($1 == "default"){print $3 ";" $5}')
DFLT_IF=${DFLT_RT#*;}
DFLT_GW=${DFLT_RT%;*}


# bring up phase1
phase1_up() {
  # check if VPN address already set up on default interface (dupe script call)
  ip addr list ${DFLT_IF} | grep -q "${INTERNAL_ADDR4}/32" && {
    echo "p1_up_down: phase1_up has already run !!!"
    exit 4
  }

  # save current resolv.conf and create new one based on info from VPN server
  [ -f /etc/resolv.conf.prevpn ] || cp /etc/resolv.conf /etc/resolv.conf.prevpn
  {
    echo "# Generated by racoon on $(date)"
    echo "search ${DEFAULT_DOMAIN}"
    for NS in ${INTERNAL_DNS4_LIST}; do
      echo "nameserver ${NS}"
    done
  } > /etc/resolv.conf

  # add VPN address to default interface
  ip addr add dev ${DFLT_IF} ${INTERNAL_ADDR4}/32
  # set up host route to VPN server
  ip route add ${REMOTE_ADDR} via ${DFLT_GW} dev ${DFLT_IF}

  if [ -n "${SPLIT_INCLUDE_CIDR}" ]; then
    # split tunnel: keep existing default, insert specific tunnel routes
    for N in ${SPLIT_INCLUDE_CIDR}; do
      ip route add ${N} via ${DFLT_GW} dev ${DFLT_IF} src ${INTERNAL_ADDR4}
    done
  else
    # full tunnel: set up any applicable exceptions...
    for N in ${SPLIT_LOCAL_CIDR}; do
      ip route add ${N} via ${DFLT_GW} dev ${DFLT_IF}
    done
    # ... then replace default route with vpn tunnel
    ip route del default
    ip route add default via ${DFLT_GW} dev ${DFLT_IF} src ${INTERNAL_ADDR4}
  fi

  # update SA database
  setkey -c << EOT
spdadd ${INTERNAL_ADDR4}/32[any] 0.0.0.0/0[any] any -P out ipsec
       esp/tunnel/${LOCAL}-${REMOTE}/require;
spdadd 0.0.0.0/0[any] ${INTERNAL_ADDR4}[any] any -P in ipsec
       esp/tunnel/${REMOTE}-${LOCAL}/require;
EOT
}

# bring down phase1
phase1_down() {
  # restore previous resolv.conf
  [ -f /etc/resolv.conf.prevpn ] && mv /etc/resolv.conf.prevpn /etc/resolv.conf

  if [ -n "${SPLIT_INCLUDE_CIDR}" ]; then
    # split tunnel: remove specific tunnel routes
    for N in ${SPLIT_INCLUDE_CIDR}; do
      ip route del ${N}
    done
  else
    # full tunnel: remove any applicable exceptions...
    for N in ${SPLIT_LOCAL_CIDR}; do
      ip route del ${N}
    done
    # ... then restore original default route
    ip route del default
    ip route add default via ${DFLT_GW} dev ${DFLT_IF}
  fi

  # remove host route to VPN server
  ip route del ${REMOTE_ADDR}
  # remove VPN address from default interface
  ip addr del dev ${DFLT_IF} ${INTERNAL_ADDR4}/32

  # clean up SA database
  # (deleteall command may be broken on Linux, use 'flush esp' as workaround)
  setkey -c << EOT
spddelete ${INTERNAL_ADDR4}/32[any] 0.0.0.0/0[any] any -P out ipsec
          esp/tunnel/${LOCAL}-${REMOTE}/require;
spddelete 0.0.0.0/0[any] ${INTERNAL_ADDR4}[any] any -P in ipsec
          esp/tunnel/${REMOTE}-${LOCAL}/require;
deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp;
deleteall ${LOCAL_ADDR} ${REMOTE_ADDR} esp; 
EOT
}


# print out parameters we received
echo "p1_up_down: $1 starting..."
echo "p1_up_down: LOCAL_ADDR = ${LOCAL_ADDR}"
echo "p1_up_down: LOCAL_PORT = ${LOCAL_PORT}"
echo "p1_up_down: REMOTE_ADDR = ${REMOTE_ADDR}"
echo "p1_up_down: REMOTE_PORT = ${REMOTE_PORT}"
echo "p1_up_down: DFLT_GW = ${DFLT_GW}"
echo "p1_up_down: DFLT_IF = ${DFLT_IF}"
echo "p1_up_down: INTERNAL_ADDR4 = ${INTERNAL_ADDR4}"
echo "p1_up_down: INTERNAL_DNS4 = ${INTERNAL_DNS4}"
echo "p1_up_down: DEFAULT_DOMAIN = ${DEFAULT_DOMAIN}"
echo "p1_up_down: SPLIT_INCLUDE_CIDR = ${SPLIT_INCLUDE_CIDR}"
echo "p1_up_down: SPLIT_LOCAL_CIDR = ${SPLIT_LOCAL_CIDR}"

# check for valid VPN address
echo ${INTERNAL_ADDR4} | grep -q '[0-9]' || {
  echo "p1_up_down: error: invalid INTERNAL_ADDR4."
  exit 1
}

# check for valid default nexthop
echo ${DFLT_GW} | grep -q '[0-9]' || {
  echo "p1_up_down: error: invalid DFLT_GW."
  exit 2
}

# main "program"
case "$1" in
  phase1_up)
    phase1_up
    ;;
  phase1_down)
    phase1_down
    ;;
  *)
    echo "p1_up_down: error: must be called by racoon w. arg=phase1_[up|down]"
    exit 3
    ;;
esac

echo "p1_up_down: $1 completed successfully."
exit 0

["ipsec-tools-0.7-cvs-deleteall.patch" (text/plain)]

diff -NarU5 ipsec-tools-0.7-cvs071026.orig/src/setkey/parse.y \
                ipsec-tools-0.7-cvs071026/src/setkey/parse.y
--- ipsec-tools-0.7-cvs071026.orig/src/setkey/parse.y	2007-07-18 08:07:52.000000000 \
                -0400
+++ ipsec-tools-0.7-cvs071026/src/setkey/parse.y	2007-10-26 22:44:18.000000000 -0400
@@ -209,15 +209,36 @@
 
 	/* deleteall command */
 deleteall_command
 	:	DELETEALL ipaddropts ipaddr ipaddr protocol_spec EOT
 		{
-			int status;
-
-			status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1);
-			if (status < 0)
+#ifndef __linux__
+			if (setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1) < 0)
+				return -1;
+#else /* __linux__ */
+	/* linux strictly adheres to RFC2367, and returns an error when we
+	 * send an SADB_DELETE request without an SPI. Therefore, we must
+	 * first retrieve a list of SPIs for all matching SADB entries, and
+	 * then delete each one separately.
+	 */
+#define MAX_SPI 1024
+			u_int32_t spi[MAX_SPI];
+			int i, n;
+
+			n = sendkeymsg_spigrep($5, $3, $4, spi, MAX_SPI);
+			if (n < 0) {
+				yyerror("too many SPIs matched");
 				return -1;
+			}
+
+			for (i = 0; i < n; i++) {
+				p_spi = spi[i];
+				if (setkeymsg_addr(SADB_DELETE,
+							$5, $3, $4, 0) < 0)
+					return -1;
+			}
+#endif /* __linux__ */
 		}
 	;
 
 	/* get command */
 get_command
diff -NarU5 ipsec-tools-0.7-cvs071026.orig/src/setkey/setkey.c \
                ipsec-tools-0.7-cvs071026/src/setkey/setkey.c
--- ipsec-tools-0.7-cvs071026.orig/src/setkey/setkey.c	2007-07-18 08:07:52.000000000 \
                -0400
+++ ipsec-tools-0.7-cvs071026/src/setkey/setkey.c	2007-10-26 22:42:40.000000000 -0400
@@ -443,10 +443,157 @@
 			fflush(stdout);
 		}
 	}
 }
 
+/* Populate 'spi' array with SPIs matching 'satype', 'srcs', and 'dsts'
+ * Return value is the number of SPIs found.
+ * If maximum capacity of 'spi' (given by 'max_spi') is exceeded, return -1
+ * On any other error, return 0.
+ */
+int
+sendkeymsg_spigrep(satype, srcs, dsts, spi, max_spi)
+	unsigned int satype;
+	struct addrinfo *srcs;
+	struct addrinfo *dsts;
+	u_int32_t *spi;
+	int max_spi;
+{
+	struct sadb_msg msg, *m;
+	char *buf;
+	size_t len;
+	ssize_t l;
+	u_char rbuf[1024 * 32];
+	int n;
+	caddr_t mhp[SADB_EXT_MAX + 1];
+	struct sadb_address *saddr;
+	struct sockaddr *s;
+	struct addrinfo *a;
+	struct sadb_sa *sa;
+
+	if (f_notreally)
+		return 0;
+
+    {
+	struct timeval tv;
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+		perror("setsockopt");
+		return 0;
+	}
+    }
+
+	msg.sadb_msg_version = PF_KEY_V2;
+	msg.sadb_msg_type = SADB_DUMP;
+	msg.sadb_msg_errno = 0;
+	msg.sadb_msg_satype = satype;
+	msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
+	msg.sadb_msg_reserved = 0;
+	msg.sadb_msg_seq = 0;
+	msg.sadb_msg_pid = getpid();
+	buf = (char *)&msg;
+	len = sizeof(msg);
+
+	if (f_verbose) {
+		kdebug_sadb(&msg);
+		printf("\n");
+	}
+	if (f_hexdump) {
+		int i;
+		for (i = 0; i < len; i++) {
+			if (i % 16 == 0)
+				printf("%08x: ", i);
+			printf("%02x ", buf[i] & 0xff);
+			if (i % 16 == 15)
+				printf("\n");
+		}
+		if (len % 16)
+			printf("\n");
+	}
+
+	if ((l = send(so, buf, len, 0)) < 0) {
+		perror("send");
+		return 0;
+	}
+
+	m = (struct sadb_msg *)rbuf;
+	n = 0;
+	do {
+		if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+			perror("recv");
+			return 0;
+		}
+
+		if (PFKEY_UNUNIT64(m->sadb_msg_len) != l) {
+			warnx("invalid keymsg length");
+			return 0;
+		}
+
+		if (f_verbose) {
+			kdebug_sadb(m);
+			printf("\n");
+		}
+
+		if (m->sadb_msg_type != SADB_DUMP) {
+			warnx("unexpected message type");
+			return 0;
+		}
+
+		if (m->sadb_msg_errno != 0) {
+			warnx("error encountered");
+			return 0;
+		}
+
+		/* match satype */
+		if (m->sadb_msg_satype != satype)
+			continue;
+
+		pfkey_align(m, mhp);
+		pfkey_check(mhp);
+
+		/* match src */
+		saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+		if (saddr == NULL)
+			continue;
+		s = (struct sockaddr *)(saddr + 1);
+		for (a = srcs; a; a = a->ai_next)
+			if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
+				break;
+		if (a == NULL)
+			continue;
+
+		/* match dst */
+		saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+		if (saddr == NULL)
+			continue;
+		s = (struct sockaddr *)(saddr + 1);
+		for (a = dsts; a; a = a->ai_next)
+			if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
+				break;
+		if (a == NULL)
+			continue;
+
+		if (n < max_spi) {
+			sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+			if (sa != NULL)
+				spi[n++] = (u_int32_t)ntohl(sa->sadb_sa_spi);
+		} else
+			return -1;
+
+		m = (struct sadb_msg *)((caddr_t)m + PFKEY_UNUNIT64(m->sadb_msg_len));
+
+		if (f_verbose) {
+			kdebug_sadb(m);
+			printf("\n");
+		}
+
+	} while (m->sadb_msg_seq);
+
+	return n;
+}
+
 int
 sendkeymsg(buf, len)
 	char *buf;
 	size_t len;
 {
@@ -504,11 +651,11 @@
 			warnx("invalid keymsg length");
 			break;
 		}
 
 		if (f_verbose) {
-			kdebug_sadb((struct sadb_msg *)rbuf);
+			kdebug_sadb(msg);
 			printf("\n");
 		}
 		if (postproc(msg, l) < 0)
 			break;
 	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);



-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php

_______________________________________________
Ipsec-tools-devel mailing list
Ipsec-tools-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ipsec-tools-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic