except socket.error, e:
logging.basicConfig()
s_log.warn("failed to connect to syslog (%s)" % e)
+s_log.addHandler(logging.StreamHandler())
+root_prefix = '' # Prefix for absolute file names, for testing.
setkey = "/usr/sbin/setkey"
self.psk_hosts = {}
self.cert_hosts = {}
- if not os.path.isdir(self.cert_dir):
+ if not os.path.isdir(root_prefix + self.cert_dir):
os.mkdir(self.cert_dir)
# Clean out stale peer certs from previous runs
- for ovs_cert in glob.glob("%s/ovs-*.pem" % self.cert_dir):
+ for ovs_cert in glob.glob("%s%s/ovs-*.pem"
+ % (root_prefix, self.cert_dir)):
try:
os.remove(ovs_cert)
except OSError:
self.commit()
def reload(self):
- exitcode = subprocess.call(["/etc/init.d/racoon", "reload"])
+ exitcode = subprocess.call([root_prefix + "/etc/init.d/racoon",
+ "reload"])
if exitcode != 0:
# Racoon is finicky about its configuration file and will
# refuse to start if it sees something it doesn't like
# (e.g., a certificate file doesn't exist). Try restarting
# the process before giving up.
s_log.warning("attempting to restart racoon")
- exitcode = subprocess.call(["/etc/init.d/racoon", "restart"])
+ exitcode = subprocess.call([root_prefix + "/etc/init.d/racoon",
+ "restart"])
if exitcode != 0:
s_log.warning("couldn't reload racoon")
def commit(self):
# Rewrite the Racoon configuration file
- conf_file = open(self.conf_file, 'w')
+ conf_file = open(root_prefix + self.conf_file, 'w')
conf_file.write(Racoon.conf_header % (self.psk_file, self.cert_dir))
for host, vals in self.cert_hosts.iteritems():
# Rewrite the pre-shared keys file; it must only be readable by root.
orig_umask = os.umask(0077)
- psk_file = open(Racoon.psk_file, 'w')
+ psk_file = open(root_prefix + Racoon.psk_file, 'w')
os.umask(orig_umask)
psk_file.write("# Generated by Open vSwitch...do not modify by hand!")
def _verify_certs(self, vals):
# Racoon will refuse to start if the certificate files don't
# exist, so verify that they're there.
- if not os.path.isfile(vals["certificate"]):
+ if not os.path.isfile(root_prefix + vals["certificate"]):
raise error.Error("'certificate' file does not exist: %s"
% vals["certificate"])
- elif not os.path.isfile(vals["private_key"]):
+ elif not os.path.isfile(root_prefix + vals["private_key"]):
raise error.Error("'private_key' file does not exist: %s"
% vals["private_key"])
if vals["peer_cert"].find("-----BEGIN CERTIFICATE-----") == -1:
raise error.Error("'peer_cert' is not in valid PEM format")
- cert = open(vals["certificate"]).read()
+ cert = open(root_prefix + vals["certificate"]).read()
if cert.find("-----BEGIN CERTIFICATE-----") == -1:
raise error.Error("'certificate' is not in valid PEM format")
- cert = open(vals["private_key"]).read()
+ cert = open(root_prefix + vals["private_key"]).read()
if cert.find("-----BEGIN RSA PRIVATE KEY-----") == -1:
raise error.Error("'private_key' is not in valid PEM format")
# The peer's certificate comes to us in PEM format as a string.
# Write that string to a file for Racoon to use.
peer_cert_file = "%s/ovs-%s.pem" % (self.cert_dir, host)
- f = open(peer_cert_file, "w")
+ f = open(root_prefix + peer_cert_file, "w")
f.write(vals["peer_cert"])
f.close()
del self.cert_hosts[host]
self.commit()
try:
- os.remove(peer_cert_file)
+ os.remove(root_prefix + peer_cert_file)
except OSError:
pass
def call_setkey(self, cmds):
try:
- p = subprocess.Popen([setkey, "-c"], stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
+ p = subprocess.Popen([root_prefix + setkey, "-c"],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
except:
- s_log.error("could not call setkey")
+ s_log.error("could not call %s%s" % (root_prefix, setkey))
sys.exit(1)
# xxx It is safer to pass the string into the communicate()
# older entry could be in a "dying" state.
spi_list = []
host_line = "%s %s" % (local_ip, remote_ip)
- results = self.call_setkey("dump ;").split("\n")
+ results = self.call_setkey("dump ;\n").split("\n")
for i in range(len(results)):
if results[i].strip() == host_line:
# The SPI is in the line following the host pair
return spi_list
def sad_flush(self):
- self.call_setkey("flush;")
+ self.call_setkey("flush;\n")
def sad_del(self, local_ip, remote_ip):
# To delete all SAD entries, we should be able to use setkey's
self.call_setkey(cmds)
def spd_flush(self):
- self.call_setkey("spdflush;")
+ self.call_setkey("spdflush;\n")
def spd_add(self, local_ip, remote_ip):
cmds = ("spdadd %s %s gre -P out ipsec esp/transport//require;\n" %
(local_ip, remote_ip))
- cmds += ("spdadd %s %s gre -P in ipsec esp/transport//require;" %
+ cmds += ("spdadd %s %s gre -P in ipsec esp/transport//require;\n" %
(remote_ip, local_ip))
self.call_setkey(cmds)
def spd_del(self, local_ip, remote_ip):
cmds = "spddelete %s %s gre -P out;\n" % (local_ip, remote_ip)
- cmds += "spddelete %s %s gre -P in;" % (remote_ip, local_ip)
+ cmds += "spddelete %s %s gre -P in;\n" % (remote_ip, local_ip)
self.call_setkey(cmds)
def add_entry(self, local_ip, remote_ip, vals):
print "usage: %s [OPTIONS] DATABASE" % sys.argv[0]
print "where DATABASE is a socket on which ovsdb-server is listening."
ovs.daemon.usage()
- print "Other options:"
- print " -h, --help display this help message"
+ print """\
+Other options:
+ --root-prefix=DIR Use DIR as alternate root directory (for testing).
+ -h, --help Display this help message."""
sys.exit(0)
def main(argv):
try:
options, args = getopt.gnu_getopt(
- argv[1:], 'h', ['help'] + ovs.daemon.LONG_OPTIONS)
+ argv[1:], 'h', ['help', 'root-prefix='] + ovs.daemon.LONG_OPTIONS)
except getopt.GetoptError, geo:
sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
sys.exit(1)
for key, value in options:
if key in ['-h', '--help']:
usage()
+ elif key == "--root-prefix":
+ global root_prefix
+ root_prefix = value
elif not ovs.daemon.parse_opt(key, value):
sys.stderr.write("%s: unhandled option %s\n"
% (ovs.util.PROGRAM_NAME, key))
--- /dev/null
+AT_BANNER([ovs-monitor-ipsec])
+
+AT_SETUP([ovs-monitor-ipsec])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+
+OVS_PKGDATADIR=`pwd`; export OVS_PKGDATADIR
+cp "$top_srcdir/vswitchd/vswitch.ovsschema" .
+
+trap 'kill `cat pid ovs-monitor-ipsec.pid`' 0
+
+mkdir etc etc/init.d etc/racoon etc/racoon/certs
+mkdir usr usr/sbin
+
+AT_DATA([etc/init.d/racoon], [dnl
+#! /bin/sh
+echo "racoon: $@" >&3
+exit 0
+])
+chmod +x etc/init.d/racoon
+
+AT_DATA([usr/sbin/setkey], [dnl
+#! /bin/sh
+exec >&3
+echo "setkey:"
+while read line; do
+ echo "> $line"
+done
+])
+chmod +x usr/sbin/setkey
+
+touch etc/racoon/certs/ovs-stale.pem
+
+ovs_vsctl () {
+ ovs-vsctl --timeout=5 --no-wait -vreconnect:ANY:emer --db=unix:socket "$@"
+}
+trim () { # Removes blank lines and lines starting with # from input.
+ sed -e '/^#/d' -e '/^[ ]*$/d' "$@"
+}
+
+###
+### Start ovsdb-server.
+###
+OVS_VSCTL_SETUP
+
+###
+### Start ovs-monitor-ipsec and wait for it to delete the stale cert.
+###
+AT_CHECK(
+ [$PYTHON $top_srcdir/debian/ovs-monitor-ipsec "--root-prefix=`pwd`" \
+ "--pidfile-name=`pwd`/ovs-monitor-ipsec.pid" \
+ unix:socket 2>log 3>actions &])
+AT_CAPTURE_FILE([log])
+AT_CAPTURE_FILE([actions])
+OVS_WAIT_UNTIL([test ! -f etc/racoon/certs/ovs-stale.pem])
+
+###
+### Add an ipsec_gre psk interface and check what ovs-monitor-ipsec does
+###
+AT_CHECK([ovs_vsctl \
+ -- add-br br0 \
+ -- add-port br0 gre0 \
+ -- set interface gre0 type=ipsec_gre \
+ options:remote_ip=1.2.3.4 \
+ options:psk=swordfish])
+OVS_WAIT_UNTIL([test -f actions && grep 'spdadd 1.2.3.4' actions >/dev/null])
+AT_CHECK([cat actions], [0], [dnl
+setkey:
+> flush;
+setkey:
+> spdflush;
+racoon: reload
+racoon: reload
+setkey:
+> spdadd 0.0.0.0/0 1.2.3.4 gre -P out ipsec esp/transport//require;
+> spdadd 1.2.3.4 0.0.0.0/0 gre -P in ipsec esp/transport//require;
+])
+AT_CHECK([trim etc/racoon/psk.txt], [0], [1.2.3.4 swordfish
+])
+AT_CHECK([trim etc/racoon/racoon.conf], [0], [dnl
+path pre_shared_key "/etc/racoon/psk.txt";
+path certificate "/etc/racoon/certs";
+remote 1.2.3.4 {
+ exchange_mode main;
+ nat_traversal on;
+ proposal {
+ encryption_algorithm aes;
+ hash_algorithm sha1;
+ authentication_method pre_shared_key;
+ dh_group 2;
+ }
+}
+sainfo anonymous {
+ pfs_group 2;
+ lifetime time 1 hour;
+ encryption_algorithm aes;
+ authentication_algorithm hmac_sha1, hmac_md5;
+ compression_algorithm deflate;
+}
+])
+
+###
+### Delete the ipsec_gre interface and check what ovs-monitor-ipsec does
+###
+AT_CHECK([ovs_vsctl del-port gre0])
+OVS_WAIT_UNTIL([test `wc -l < actions` -ge 17])
+AT_CHECK([sed '1,9d' actions], [0], [dnl
+racoon: reload
+setkey:
+> spddelete 0.0.0.0/0 1.2.3.4 gre -P out;
+> spddelete 1.2.3.4 0.0.0.0/0 gre -P in;
+setkey:
+> dump ;
+setkey:
+> dump ;
+])
+AT_CHECK([trim etc/racoon/psk.txt], [0], [])
+AT_CHECK([trim etc/racoon/racoon.conf], [0], [dnl
+path pre_shared_key "/etc/racoon/psk.txt";
+path certificate "/etc/racoon/certs";
+sainfo anonymous {
+ pfs_group 2;
+ lifetime time 1 hour;
+ encryption_algorithm aes;
+ authentication_algorithm hmac_sha1, hmac_md5;
+ compression_algorithm deflate;
+}
+])
+
+###
+### Add ipsec_gre certificate interface and check what ovs-monitor-ipsec does
+###
+AT_DATA([cert.pem], [dnl
+-----BEGIN CERTIFICATE-----
+(not a real certificate)
+-----END CERTIFICATE-----
+])
+AT_DATA([key.pem], [dnl
+-----BEGIN RSA PRIVATE KEY-----
+(not a real private key)
+-----END RSA PRIVATE KEY-----
+])
+AT_CHECK([ovs_vsctl \
+ -- add-port br0 gre1 \
+ -- set Interface gre1 type=ipsec_gre \
+ options:remote_ip=2.3.4.5 \
+ options:peer_cert='"-----BEGIN CERTIFICATE-----
+(not a real peer certificate)
+-----END CERTIFICATE-----
+"' \
+ options:certificate='"/cert.pem"' \
+ options:private_key='"/key.pem"'])
+OVS_WAIT_UNTIL([test `wc -l < actions` -ge 21])
+AT_CHECK([sed '1,17d' actions], [0], [dnl
+racoon: reload
+setkey:
+> spdadd 0.0.0.0/0 2.3.4.5 gre -P out ipsec esp/transport//require;
+> spdadd 2.3.4.5 0.0.0.0/0 gre -P in ipsec esp/transport//require;
+])
+AT_CHECK([trim etc/racoon/psk.txt], [0], [])
+AT_CHECK([trim etc/racoon/racoon.conf], [0], [dnl
+path pre_shared_key "/etc/racoon/psk.txt";
+path certificate "/etc/racoon/certs";
+remote 2.3.4.5 {
+ exchange_mode main;
+ nat_traversal on;
+ ike_frag on;
+ certificate_type x509 "/cert.pem" "/key.pem";
+ my_identifier asn1dn;
+ peers_identifier asn1dn;
+ peers_certfile x509 "/etc/racoon/certs/ovs-2.3.4.5.pem";
+ verify_identifier on;
+ proposal {
+ encryption_algorithm aes;
+ hash_algorithm sha1;
+ authentication_method rsasig;
+ dh_group 2;
+ }
+}
+sainfo anonymous {
+ pfs_group 2;
+ lifetime time 1 hour;
+ encryption_algorithm aes;
+ authentication_algorithm hmac_sha1, hmac_md5;
+ compression_algorithm deflate;
+}
+])
+AT_CHECK([cat etc/racoon/certs/ovs-2.3.4.5.pem], [0], [dnl
+-----BEGIN CERTIFICATE-----
+(not a real peer certificate)
+-----END CERTIFICATE-----
+])
+
+###
+### Delete the ipsec_gre certificate interface.
+###
+AT_CHECK([ovs_vsctl del-port gre1])
+OVS_WAIT_UNTIL([test `wc -l < actions` -ge 29])
+AT_CHECK([sed '1,21d' actions], [0], [dnl
+racoon: reload
+setkey:
+> spddelete 0.0.0.0/0 2.3.4.5 gre -P out;
+> spddelete 2.3.4.5 0.0.0.0/0 gre -P in;
+setkey:
+> dump ;
+setkey:
+> dump ;
+])
+AT_CHECK([trim etc/racoon/psk.txt], [0], [])
+AT_CHECK([trim etc/racoon/racoon.conf], [0], [dnl
+path pre_shared_key "/etc/racoon/psk.txt";
+path certificate "/etc/racoon/certs";
+sainfo anonymous {
+ pfs_group 2;
+ lifetime time 1 hour;
+ encryption_algorithm aes;
+ authentication_algorithm hmac_sha1, hmac_md5;
+ compression_algorithm deflate;
+}
+])
+AT_CHECK([test ! -f etc/racoon/certs/ovs-2.3.4.5.pem])
+
+AT_CLEANUP