#!/bin/sh

# A collection of whack sequences to test Pluto.
# Generally, we command the west Pluto to negotiate with east.
# Sometimes north and south come into play, but not as participants.

set -u

. CONFIG

WESTHOST="--host $WESTIP --ikeport $IKEPORT"
WESTNET="$WESTHOST --client $WESTSUBNET"

EASTHOST="--host $EASTIP --ikeport $IKEPORT"
EASTNET="$EASTHOST --client $EASTSUBNET"

ANYHOST="--host %any --ikeport $IKEPORT"
OPPO="--host %opportunistic --ikeport $IKEPORT"
OPPONARROW="$OPPO --client 127.0.0.0/8"
OPPOMISS="$OPPO --client 10.0.0.0/8"
GROUP="--host %group --ikeport $IKEPORT"
OPPOGROUP="--host %opportunisticgroup --ikeport $IKEPORT"

WHACKWEST="${WESTWHACK:-$WHACK} --ctlbase ./pluto.west"
WHACKEAST="${EASTWHACK:-$WHACK} --ctlbase ./pluto.east"

# run of the mill lifetimes
NORMALMARG=350
NORMALIKE=900
TIMES="--rekeymargin $NORMALMARG --ikelifetime $NORMALIKE --ipseclifetime 800"

# half size, to be shorter
SHORTMARG=175
SHORTIKE=450
SHORTIPSEC=400
SHORTTIMES="--rekeymargin $SHORTMARG --ikelifetime $SHORTIKE --ipseclifetime $SHORTIPSEC"

# really small so we're willing to sleep through a keying interval
TINYIPSECLIFETIME=40
TINYTIMES="--rekeymargin 17 --ikelifetime 45 --ipseclifetime $TINYIPSECLIFETIME"

TIMES0="$TIMES --keyingtries 0"
TIMES1="$TIMES --keyingtries 1"
TIMES2="$TIMES --keyingtries 2"

LIST="1 2 3 4 5"

# dumb boilerplate
TO="--updown silly --to --updown sally"

function whackwest() {
	$WHACKWEST "$@"
	}

function whackeast() {
	$WHACKEAST "$@"
	}

function perform() {
	echo "$@"
	"$@" || echo RC: $?
	}

function me() {
	perform whackwest "$@"
	}

function him() {
	perform whackeast "$@"
	}

function both() {
	perform whackwest "$@"
	perform whackeast "$@"
	}

# Grab the lifetime setting actually in states.
# Turn them into shell variable assignments suitable for eval ``.
function grab_lifetimes() {
	( me --status ; him --status ) | sed -n -e \
		'/STATE_/ {
			s/.*MAIN/ISAKMP/
			s/.*QUICK/IPsec/
			s/_I[0-4]/_I!/
			s/_R[0-4]/_R!/
			s/!.*EVENT_SA_\([^ ]*\)/_\1!/
			s/! in \([0-9]*\)s.*/=\1/
			p
			}'
	}

# Check if lifetime is close to predicted time
# Can't be more, but might be a bit less.
# A bit is 3 seconds, for now.
# Must not print variable values unless we have an error condition.
function notcloseto() {
	if expr '(' $1 ')' '>' '(' $2 ')' >/dev/null
	then
		echo bad $3: $1 '>' $2
		return 0
	elif expr '(' $1 ')' '<' '(' $2 ')' - 3 >/dev/null
	then
		echo bad $3: $1 '<' $2 - 3
		return 0
	else
		echo good $3: close to $2
		return 1
	fi
	}

# don't indent for: too much waste space
for i
do

case "$i" in
*-dnsrsa*)	RSADNS="--dnskeyondemand" ;;
*)	RSADNS="";;
esac

# more boilerplate
TO_RSA="$RSADNS $TO $RSADNS"
	
case "$i" in
listen)	both --listen
	;;
kall)	both --keyid 127.95.7.2 --pubkeyrsa 0sAQOeSJscIy2XZHfs+PODDqdgJR2FmdfRNqzURVL5q2fesMHmibMLPM5cTPx2HvYKBX3YyB+BdHoojmFNixV+RTrKyyN0Og4PYwhdw0FUApDvOg7KYe1CeLUeTAUzT5Pq7MdclRW5bYY84hXSfKgaPwPTwuiLKEnVdbhGgwxqwfQ6ow==
	both --keyid @east.example.com --pubkeyrsa 0sAQNWmttqbM8nIypsHEULynOagFyV1MQ+/1yF5sa32abxBb2fimah7NsHM9l/KpNo7RGtiP0L6triedsZ0xz1Maa4DPnZlrtexu5uIH+FH34SUr7Xe2RcHnLVOznHMzacgcjrOUvV/nA9OEGvm7vRsMAWm/VjNuNugogFreiYEpFMQQ==
	both --keyid 127.95.7.3 --pubkeyrsa 0sAQN4JFU9gRnG336z1n1cV2LA6ACi1TjXfv3pvl6DRqa6uqBFM9RO4oArPc6FsBkBwEmMr8cpeFn4mVaepVe63qnvmQbGXVcRwhx0a509M824HjnyM04Xpoh2UuP/Mhnkm1cynunRuyGqXaZhlj4s+GbcOxPXhopz94wer+Qs/qvGqw==
	both --keyid @north.example.com --pubkeyrsa 0sAQN4JFU9gRnG336z1n1cV2LA6ACi1TjXfv3pvl6DRqa6uqBFM9RO4oArPc6FsBkBwEmMr8cpeFn4mVaepVe63qnvmQbGXVcRwhx0a509M824HjnyM04Xpoh2UuP/Mhnkm1cynunRuyGqXaZhlj4s+GbcOxPXhopz94wer+Qs/qvGqw==
	both --keyid 127.95.7.4 --pubkeyrsa 0sAQOKe6+kbDtp4PB8NZshjCBw8z5wuGCAddokgSDATW47tNmQhUvzlnT1ia1ZsyiRFph1LJkz+A0bkbOhPr1vWUJHK6/s+Y8Rf7GSZC0Fi5Fr4DgpWwswzFaLl4baRfeu8z4k147dtSoG4K/6UfQ+IbqML5lwm92uRqONszbn/PDDPQ==
	both --keyid @south.example.com --pubkeyrsa 0sAQOKe6+kbDtp4PB8NZshjCBw8z5wuGCAddokgSDATW47tNmQhUvzlnT1ia1ZsyiRFph1LJkz+A0bkbOhPr1vWUJHK6/s+Y8Rf7GSZC0Fi5Fr4DgpWwswzFaLl4baRfeu8z4k147dtSoG4K/6UfQ+IbqML5lwm92uRqONszbn/PDDPQ==
	both --keyid 127.95.7.1 --pubkeyrsa 0sAQOOyFBeFFr9CWXgn1aOEvTr98HG4inSckTXlyYi5x85G+Q1+PZ/roqB3OtnRS2XbXFb3n92QjZMJ403wQUwMAt6uzXzXDle5VvFn7cVXq3ch0jqQUxIFcdIIFR2wtkxvAr20xSOHNF/ozmKVZLkrHLu4RvVCCbSNa5toqLXblkcOQ==
	both --keyid @west.example.com --pubkeyrsa 0sAQOFtqrs57eghHmYREoCu1iGn4kXd+a6yT7wCFUk54d9i08mR4h5uFKPhc9fq78XNqz1AhrBH3SRcWAfJ8DaeGvZ0ZvCrTQZn+RJzX1FQ4fjuGBO0eup2XUMsYDw01PFzQ9O4qlwly6niOcMTxvbWgGcl+3DYfRvHgxet8kNtfqzHQ==
	;;
shutdown)	both --shutdown
	;;
status)	both --status
	;;

# "isakmp": ISAKMP SA only; PSK or RSA

disakmp-psk) both --name isakmp-psk --psk $EASTHOST $TO $WESTHOST $TIMES2 ;;
xisakmp-psk) me --name isakmp-psk --initiate ;;

disakmp-rsa|disakmp-dnsrsa)
	both --name isakmp-rsa --rsa $EASTHOST $TO_RSA $WESTHOST $TIMES2 ;;
xisakmp-rsa|xisakmp-dnsrsa) me --name isakmp-rsa --initiate ;;

# Regression test: the two sides use different cases for the same ID
# This caused authentication failures until 2002 May 29
disakmp-rsa-case|disakmp-dnsrsa-case)
	me --name isakmp-rsa --rsa $EASTHOST \
		$TO_RSA --id=@west.example.com $WESTHOST $TIMES2
	him --name isakmp-rsa --rsa $EASTHOST \
		$TO_RSA --id=@WEST.example.com $WESTHOST $TIMES2
	;;
xisakmp-rsa-case|xisakmp-dnsrsa-case) me --name isakmp-rsa --initiate ;;

# "ipsec": IPsec SA

dipsec-psk)
	both --name ipsec-psk --delete --psk \
		$EASTNET $TO $WESTNET \
		--authenticate --encrypt --pfs $TIMES2
	;;
xipsec-psk)
	me --name ipsec-psk --initiate
	;;

dipsec-rsa|dipsec-dnsrsa)
	both --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES2
	;;
xipsec-rsa|xipsec-dnsrsa)
	me --name ipsec-rsa --initiate
	;;

dipsec-rsa-delete|dipsec-dnsrsa-delete)
	both --name ipsec-rsa-delete --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES2
	;;
xipsec-rsa-delete|xipsec-dnsrsa-delete)
	me --name ipsec-rsa-delete --initiate
	me --name ipsec-rsa-delete --terminate
	;;

# Like xipsec-rsa EXCEPT we have the wrong public key for West.
# Failure takes time, so not automatically run.
dipsec-wk-rsa|dipsec-wk-dnsrsa)
	echo NOTE: failure is expected because we use the wrong key
	both --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES2
	;;
xipsec-wk-rsa|xipsec-wk-dnsrsa)
		# jam bad public key for east
	me --keyid 127.95.7.2 --pubkeyrsa 0sAQOKe6+kbDtp4PB8NZshjCBw8z5wuGCAddokgSDATW47tNmQhUvzlnT1ia1ZsyiRFph1LJkz+A0bkbOhPr1vWUJHK6/s+Y8Rf7GSZC0Fi5Fr4DgpWwswzFaLl4baRfeu8z4k147dtSoG4K/6UfQ+IbqML5lwm92uRqONszbn/PDDPQ==
	me --keyid @east.example.com --pubkeyrsa 0sAQOKe6+kbDtp4PB8NZshjCBw8z5wuGCAddokgSDATW47tNmQhUvzlnT1ia1ZsyiRFph1LJkz+A0bkbOhPr1vWUJHK6/s+Y8Rf7GSZC0Fi5Fr4DgpWwswzFaLl4baRfeu8z4k147dtSoG4K/6UfQ+IbqML5lwm92uRqONszbn/PDDPQ==
	me --name ipsec-rsa --initiate
	;;

# like dipsec-rsa, except compression is specified
dipsec-rsa-c|dipsec-dnsrsa-c)
	both --name ipsec-rsa-c --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --compress $TIMES2
	;;
xipsec-rsa-c|xipsec-dnsrsa-c)
	me --name ipsec-rsa-c --initiate
	;;

# Like dipsec-rsa, except times are fiddled to see if Responder
# lifetimes reflect negotiation.
# Responder should use the shorter of the negotiated (dictated) and
# --*lifetime.
# ipsec-rsa-time-neg: him (Responder) uses negotiated lifetime -- values from Initiator
# ipsec-rsa-time-trunc: him truncates lifetime to match his connection
# we set rekeyfuzz to 0 to make resulting deadlines more deterministic

dipsec-rsa-time-neg)
	# Initiator lifetimess shorter: Responder must reflect these
	me --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $SHORTTIMES --keyingtries 2
	him --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES --keyingtries 2 \
		--rekeyfuzz 0
	;;
xipsec-rsa-time-neg)
	me --name ipsec-rsa --initiate

	# Check that the Responder's lifetimes are plausible.
	# They should be close to and no more than the amount specified
	# by the Initiator,
	# and a lot less than the amount specified in the connection.
	# We want:
	#	ISAKMP_R_REPLACE closeto SHORTIKE - NORMALMARG/2
	#	IPsec_R_REPLACE closeto SHORTIPSEC - NORMALMARG/2
	# Must not print variable values unless we have an error condition.

	eval `grab_lifetimes`

	if notcloseto $ISAKMP_R_REPLACE "$SHORTIKE - $NORMALMARG / 2" ISAKMP_R_REPLACE
	then
		echo bad: Responder did not reduce ISAKMP lifetime to match Initiator
		me --status ; him --status
	fi

	if notcloseto $IPsec_R_REPLACE "$SHORTIPSEC - $NORMALMARG / 2" IPsec_R_REPLACE
	then
		echo bad: Responder did not reduce IPsec lifetime to match Initiator
		me --status ; him --status
	fi
	;;

dipsec-rsa-time-trunc)
	# Responder lifetimess shorter: Responder must reflect these
	me --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES --keyingtries 2
	him --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $SHORTTIMES --keyingtries 2 \
		--rekeyfuzz 0
	;;
xipsec-rsa-time-trunc)
	me --name ipsec-rsa --initiate

	# Check that the Responder's lifetimes are plausible.
	# They should be close to and no more than the amount specified
	# in the connection,
	# and a lot less than the amount specified by the Initiator.
	# We want:
	#	ISAKMP_R_REPLACE closeto SHORTIKE - SHORTMARG/2
	#	IPsec_R_REPLACE closeto SHORTIPSEC - SHORTMARG/2
	# Must not print variable values unless we have an error condition.

	eval `grab_lifetimes`

	if notcloseto $ISAKMP_R_REPLACE "$SHORTIKE - $SHORTMARG / 2" ISAKMP_R_REPLACE
	then
		echo bad: Responder did not reduce ISAKMP lifetime to match connection
		me --status ; him --status
	fi

	if notcloseto $IPsec_R_REPLACE "$SHORTIPSEC - $SHORTMARG / 2" IPsec_R_REPLACE
	then
		echo bad: Responder did not reduce IPsec lifetime to match connection
		me --status ; him --status
	fi
	;;

# --dontrekey mixed with lifetime negotiation
# Much like ipsec-rsa-time-neg except we expect EXPIRE

dipsec-rsa-time-neg-dontrekey)
	# Initiator lifetimess shorter: Responder must reflect these
	me --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $SHORTTIMES --keyingtries 2
	him --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES --keyingtries 2 \
		--rekeyfuzz 0 --dontrekey
	;;
xipsec-rsa-time-neg-dontrekey)
	me --name ipsec-rsa --initiate

	# Check that the Responder's lifetimes are plausible.
	# They should be close to and no more than the amount specified
	# by the Initiator,
	# and a lot less than the amount specified in the connection.
	# We want:
	#	ISAKMP_R_EXPIRE closeto SHORTIKE
	#	IPsec_R_EXPIRE closeto SHORTIPSEC
	# Must not print variable values unless we have an error condition.

	eval `grab_lifetimes`

	if notcloseto $ISAKMP_R_EXPIRE "$SHORTIKE" ISAKMP_R_EXPIRE
	then
		echo bad: Responder did not reduce ISAKMP lifetime to match Initiator
		me --status ; him --status
	fi

	if notcloseto $IPsec_R_EXPIRE "$SHORTIPSEC" IPsec_R_EXPIRE
	then
		echo bad: Responder did not reduce IPsec lifetime to match Initiator
		me --status ; him --status
	fi
	;;

# --dontrekey mixed with lifetime truncation.
# Even though we specify no rekeying, if the Responder has a shorter
# ipseclifetime it must rekey.  But not otherwise.
# Variant of ipsec-rsa-time-trunc

dipsec-rsa-time-trunc-dontrekey)
	# Responder lifetimes are shorter: Responder must reflect these AND the negotiated values!
	# For IKE, we accept the longer time and EXPIRE on it.
	# For IPsec, we use the shorter time but REPLACE on it, even though we are --dontrekey
	me --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $TIMES --keyingtries 2
	him --name ipsec-rsa --delete --rsa \
		$EASTNET $TO_RSA $WESTNET \
		--authenticate --encrypt --pfs $SHORTTIMES --keyingtries 2 \
		--rekeyfuzz 0 --dontrekey
	;;
xipsec-rsa-time-trunc-dontrekey)
	me --name ipsec-rsa --initiate

	# Check that the Responder's lifetimes are plausible.
	# ISAKMP lifetime should EXPIRE when Initiator says.
	# IPsec lifetime should REPLACE when Responder says.
	#
	# We want:
	#	ISAKMP_R_EXPIRE closeto NORMALIKE
	#	IPsec_R_REPLACE closeto SHORTIPSEC - SHORTMARG/2
	# Must not print variable values unless we have an error condition.

	eval `grab_lifetimes`

	if notcloseto $ISAKMP_R_EXPIRE "$NORMALIKE" ISAKMP_R_EXPIRE
	then
		echo bad: Responder did not extend ISAKMP lifetime to match Initiator
	fi

	if notcloseto $IPsec_R_REPLACE "$SHORTIPSEC - $SHORTMARG / 2" IPsec_R_REPLACE
	then
		echo bad: Responder did not reduce IPsec lifetime to match connection
	fi
	;;

# Road Warrior:

dipsec-psk-rw)
	me --name ipsec-psk-rw --delete --psk \
		$WESTNET $TO $EASTNET \
		--encrypt $TIMES2
	him --name ipsec-psk-rw --delete --psk \
		$ANYHOST --client $WESTSUBNET \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-psk-rw)
	me --name ipsec-psk-rw --initiate
	;;

# although an ID payload comes too late for PSK,
# it is legal.
dipsec-psk-id-rw)
	me --name ipsec-psk-id-rw --delete --psk \
		$WESTNET --id=@west.example.com $TO $EASTNET \
		--encrypt $TIMES2
	him --name ipsec-psk-id-rw --delete --psk \
		$ANYHOST --id=@west.example.com --client $WESTSUBNET \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-psk-id-rw)
	me --name ipsec-psk-id-rw --initiate
	;;

dipsec-rsa-rw|dipsec-dnsrsa-rw)
	me --name ipsec-rsa-rw --delete --rsa \
		$WESTNET $TO_RSA $EASTNET \
		--encrypt $TIMES2
	him --name ipsec-rsa-rw --delete --rsa \
		$ANYHOST --client $WESTSUBNET \
		$TO_RSA $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-rsa-rw|xipsec-dnsrsa-rw)
	me --name ipsec-rsa-rw --initiate
	;;

# Opportunism
# --pfs and --rsa required

dipsec-oppo)
	# self
	me --name ipsec-oppo-me --delete --rsa --pfs \
		$WESTHOST --nexthop $ROUTER \
		$TO $OPPO \
		--encrypt $TIMES2
	# clients
	me --name ipsec-oppo-mine --delete --rsa --pfs \
		$WESTNET --nexthop $ROUTER \
		$TO $OPPO \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-me --delete --rsa --pfs \
		$OPPO \
		$TO $EASTHOST --nexthop $ROUTER \
		--encrypt $TIMES2
	# clients
	him --name ipsec-oppo-mine --delete --rsa --pfs \
		$OPPO \
		$TO $EASTNET --nexthop $ROUTER \
		--encrypt $TIMES2
	;;
xipsec-oppo)
	me --route --name ipsec-oppo-me
	me --route --name ipsec-oppo-mine
	# host to host
	me --oppohere $WESTIP --oppothere $EASTIP

	# host to client
	me --oppohere $WESTIP --oppothere $TRURO

	# client to host
	me --oppohere $VANCOUVER --oppothere $EASTIP

	# client to client
	me --oppohere $VICTORIA --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere 0.0.0.0 --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere $VICTORIA --oppothere 0.0.0.0

	# 033 Can't Opportunistically initiate for 127.95.7.22 to 127.95.7.10: no Opportunistic template covers them
	me --oppohere $ANTIGONISH --oppothere $VICTORIA

	# 033 Can't Opportunistically initiate for 127.95.7.10 to 127.95.7.23: no host 23.7.95.127.in-addr.arpa. for TXT record
	me --oppohere $VICTORIA --oppothere $ATLANTIS

	# Responder says: "ipsec-oppo-me" 127.95.7.1 0.0.0.0/32 #1: gateway 127.95.7.1 claims client 127.95.7.8, but DNS for client fails to confirm: no host 8.7.95.127.in-addr.arpa. for TXT record
	# Initiator slowly times out.
	# me --oppohere $VANISHED --oppothere $ANTIGONISH
	;;

# exactly like ipsec-oppo, except opportunism is limited to narrow target
dipsec-oppo-narrow)
	# self
	me --name ipsec-oppo-me --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPONARROW \
		--encrypt $TIMES2
	# clients
	me --name ipsec-oppo-mine --delete --rsa --pfs \
		$WESTNET --nexthop %direct \
		$TO $OPPONARROW \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-me --delete --rsa --pfs \
		$OPPONARROW \
		$TO $EASTHOST --nexthop %direct \
		--encrypt $TIMES2
	# clients
	him --name ipsec-oppo-mine --delete --rsa --pfs \
		$OPPONARROW \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-oppo-narrow)
	# host to host
	me --oppohere $WESTIP --oppothere $EASTIP

	# host to client
	me --oppohere $WESTIP --oppothere $TRURO

	# client to host
	me --oppohere $VANCOUVER --oppothere $EASTIP

	# client to client
	me --oppohere $VICTORIA --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere 0.0.0.0 --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere $VICTORIA --oppothere 0.0.0.0

	# 033 no suitable connection for opportunism between 127.95.7.22 and 127.95.7.10 with 127.95.7.1 as peer
	me --oppohere $ANTIGONISH --oppothere $VICTORIA

	# 033 Can't Opportunistically initiate for 127.95.7.10 to 127.95.7.23: no host 23.7.95.127.in-addr.arpa. for TXT record
	me --oppohere $VICTORIA --oppothere $ATLANTIS

	# Responder says: "ipsec-oppo-me" 127.95.7.1 0.0.0.0/32 #1: gateway 127.95.7.1 claims client 127.95.7.8, but DNS for client fails to confirm: no host 8.7.95.127.in-addr.arpa. for TXT record
	# Initiator slowly times out.
	# me --oppohere $VANISHED --oppothere $ANTIGONISH
	;;

# exactly like ipsec-oppo-narrow, except real target isn't in range
dipsec-oppo-miss)
	# self
	me --name ipsec-oppo-me --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPOMISS \
		--encrypt $TIMES2
	# clients
	me --name ipsec-oppo-mine --delete --rsa --pfs \
		$WESTNET --nexthop %direct \
		$TO $OPPOMISS \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-me --delete --rsa --pfs \
		$OPPOMISS \
		$TO $EASTHOST --nexthop %direct \
		--encrypt $TIMES2
	# clients
	him --name ipsec-oppo-mine --delete --rsa --pfs \
		$OPPOMISS \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-oppo-miss)
	# host to host
	me --oppohere $WESTIP --oppothere $EASTIP

	# host to client
	me --oppohere $WESTIP --oppothere $TRURO

	# client to host
	me --oppohere $VANCOUVER --oppothere $EASTIP

	# client to client
	me --oppohere $VICTORIA --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere 0.0.0.0 --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere $VICTORIA --oppothere 0.0.0.0

	# 033 no suitable connection for opportunism between 127.95.7.22 and 127.95.7.10 with 127.95.7.1 as peer
	me --oppohere $ANTIGONISH --oppothere $VICTORIA

	# 033 Can't Opportunistically initiate for 127.95.7.10 to 127.95.7.23: no host 23.7.95.127.in-addr.arpa. for TXT record
	me --oppohere $VICTORIA --oppothere $ATLANTIS

	# Responder says: "ipsec-oppo-me" 127.95.7.1 0.0.0.0/32 #1: gateway 127.95.7.1 claims client 127.95.7.8, but DNS for client fails to confirm: no host 8.7.95.127.in-addr.arpa. for TXT record
	# Initiator slowly times out.
	# me --oppohere $VANISHED --oppothere $ANTIGONISH
	;;

# opportunism both ways at once
# This is a regression test: asynchrony introduced with ADNS invalidated some assumptions.
# Use distinct names to make log clearer.
# Doesn't fit into framework, so not automatically run.
dipsec-oppo-race)
	# self
	me --name ipsec-oppo-west --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPO \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-east --delete --rsa --pfs \
		$OPPO \
		$TO $EASTHOST --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-oppo-race)
	# host to host
	# Use & to allow initiation to be interleaved with responding.
	# "sleep 1" is to make sure (!) that initiation gets started.
	# Delay our ADNS, but only for first query (TXT, initiation).
	me --impair-delay-adns-txt-answer --debug-all --debug-private
	me --oppohere $WESTIP --oppothere $EASTIP &
	sleep 1
	me --debug-all --debug-private
	him  --oppohere $EASTIP --oppothere $WESTIP
	wait
	;;

# similar to dipsec-oppo-race, but east is SG for truro
# Start west initiating first; responding happens within
# timespan of initiation.
dipsec-oppo-race-rini-net)
	# self
	me --name ipsec-oppo-west --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPO \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-eastnet --delete --rsa --pfs \
		$OPPO \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-oppo-race-rini-net)
	# host to host
	# Use & to allow initiation to be interleaved with responding.
	# "sleep 1" is to make sure (!) that initiation gets started.
	# Delay our ADNS, but only for first query (TXT, initiation).
	me --impair-delay-adns-txt-answer --debug-all --debug-private
	me --oppohere $WESTIP --oppothere $TRURO &
	sleep 1
	me --debug-all --debug-private
	him  --oppohere $TRURO --oppothere $WESTIP
	wait
	;;

# similar to dipsec-oppo-race-net, but reverse order of race:
# Start west responding first; initiation happens within
# timespan of responding.
# This test would drive 1.98 to assertion failure
# if the impairment mechanism were in 1.98:
# ASSERTION FAILED at ipsec_doi.c:2991: gateways_from_dns == NULL
dipsec-oppo-race-iinr-net)
	# self
	me --name ipsec-oppo-west --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPO \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-eastnet --delete --rsa --pfs \
		$OPPO \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-oppo-race-iinr-net)
	# host to host
	# Use & to allow initiation to be interleaved with responding.
	# "sleep 1" is to make sure (!) that initiation gets started.
	# Delay our ADNS, but only for TXT query (second, responding).
	me --impair-delay-adns-txt-answer --debug-all --debug-private
	him  --oppohere $TRURO --oppothere $WESTIP &
	sleep 1
	me --debug-all --debug-private
	me --oppohere $WESTIP --oppothere $TRURO
	wait
	;;

# same as ipsec-oppo-race, but strictly sequential

dipsec-oppo-seq)
	# self
	me --name ipsec-oppo-west --delete --rsa --pfs \
		$WESTHOST --nexthop $ROUTER \
		$TO $OPPO \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-east --delete --rsa --pfs \
		$OPPO \
		$TO $EASTHOST --nexthop $ROUTER \
		--encrypt $TIMES2
	;;
xipsec-oppo-seq)
	me --route --name ipsec-oppo-west
	him --route --name ipsec-oppo-east
	# host to host
	me --oppohere $WESTIP --oppothere $EASTIP
	him  --oppohere $EASTIP --oppothere $WESTIP
	;;

# twice the same way

dipsec-oppo-twice)
	# self
	me --name ipsec-oppo-west --delete --rsa --pfs \
		$WESTHOST --nexthop $ROUTER \
		$TO $OPPO \
		--encrypt $TIMES2
	# self
	him --name ipsec-oppo-east --delete --rsa --pfs \
		$OPPO \
		$TO $EASTHOST --nexthop $ROUTER \
		--encrypt $TIMES2
	;;
xipsec-oppo-twice)
	me --route --name ipsec-oppo-west
	# host to host
	me --oppohere $WESTIP --oppothere $EASTIP
	me --oppohere $WESTIP --oppothere $EASTIP
	# both --status
	;;

# stipple: test opportunism by trying a bunch of targets
# Too slow so not automatically run.

dstipple-serial|dstipple-parallel)
	# self
	me --name ipsec-oppo-me --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPO \
		--encrypt $TIMES2
	;;
xstipple-serial)
	n=10
	a=192.139.70.1
	while expr $n > 0 >/dev/null
	do
		n=`expr $n - 1`
		me --oppohere $WESTIP --oppothere $a
		a=`ipnext $a`
	done
	;;
xstipple-parallel)
	n=10
	a=192.139.70.1
	while expr $n > 0 >/dev/null
	do
		n=`expr $n - 1`
		me --oppohere $WESTIP --oppothere $a &
		a=`ipnext $a`
	done
	wait
	;;

# foodgroups tests

# oe food group
doe)
	# self
	me --name oe --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPOGROUP \
		--encrypt $TIMES2
	him --name oe --delete --rsa --pfs \
		$EASTHOST --nexthop %direct \
		$TO $OPPOGROUP \
		--encrypt $TIMES2
	;;
xoe)
	both --route --name oe
	;;

# clear food group
dclear)
	me --name clear --delete \
		$WESTHOST --nexthop %direct \
		$TO $GROUP \
		--pass
	him --name clear --delete \
		$EASTHOST --nexthop %direct \
		$TO $GROUP \
		--pass
	;;
xclear)
	both --route --name clear
	;;

# block food group
dblock)
	me --name block --delete \
		$WESTHOST --nexthop %direct \
		$TO $GROUP \
		--drop
	him --name block --delete \
		$EASTHOST --nexthop %direct \
		$TO $GROUP \
		--drop
	;;
xblock)
	both --route --name block
	;;

# reject food group
dreject)
	me --name reject --delete \
		$WESTHOST --nexthop %direct \
		$TO $GROUP \
		--reject
	him --name clear --delete \
		$EASTHOST --nexthop %direct \
		$TO $GROUP \
		--reject
	;;
xreject)
	both --route --name reject
	;;

# exactly like ipsec-oppo-narrow, except real target comes from foodgroup
dipsec-oppo-group)
	# self
	me --name opportunity --delete --rsa --pfs \
		$WESTHOST --nexthop %direct \
		$TO $OPPOGROUP \
		--encrypt $TIMES2
	# clients
	me --name opportunity-mine --delete --rsa --pfs \
		$WESTNET --nexthop %direct \
		$TO $OPPOGROUP \
		--encrypt $TIMES2
	# self
	him --name opportunity --delete --rsa --pfs \
		$OPPOGROUP \
		$TO $EASTHOST --nexthop %direct \
		--encrypt $TIMES2
	# clients
	him --name opportunity-mine --delete --rsa --pfs \
		$OPPOGROUP \
		$TO $EASTNET --nexthop %direct \
		--encrypt $TIMES2
	;;
xipsec-oppo-group)
	# host to host
	me --oppohere $WESTIP --oppothere $EASTIP

	# host to client
	me --oppohere $WESTIP --oppothere $TRURO

	# client to host
	me --oppohere $VANCOUVER --oppothere $EASTIP

	# client to client
	me --oppohere $VICTORIA --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere 0.0.0.0 --oppothere $ANTIGONISH

	# whack error: 0.0.0.0 or 0::0 isn't a valid client address "0.0.0.0"
	# me --oppohere $VICTORIA --oppothere 0.0.0.0

	# 033 no suitable connection for opportunism between 127.95.7.22 and 127.95.7.10 with 127.95.7.1 as peer
	me --oppohere $ANTIGONISH --oppothere $VICTORIA

	# 033 Can't Opportunistically initiate for 127.95.7.10 to 127.95.7.23: no host 23.7.95.127.in-addr.arpa. for TXT record
	me --oppohere $VICTORIA --oppothere $ATLANTIS

	# Responder says: "ipsec-oppo-me" 127.95.7.1 0.0.0.0/32 #1: gateway 127.95.7.1 claims client 127.95.7.8, but DNS for client fails to confirm: no host 8.7.95.127.in-addr.arpa. for TXT record
	# Initiator slowly times out.
	# me --oppohere $VANISHED --oppothere $ANTIGONISH
	;;

*)
	echo "$0: $i unknown"
	exit 1
	;;
esac
done
