[Cluster-devel] cluster/fence/agents/xvm Makefile README TODO ...

lhh at sourceware.org lhh at sourceware.org
Fri Dec 1 15:49:41 UTC 2006


CVSROOT:	/cvs/cluster
Module name:	cluster
Branch: 	RHEL4
Changes by:	lhh at sourceware.org	2006-12-01 15:49:38

Added files:
	fence/agents/xvm: Makefile README TODO debug.c fence_xvm.c 
	                  ip_lookup.c ip_lookup.h mcast.c mcast.h 
	                  options.c options.h simple_auth.c 
	                  simple_auth.h tcp.c tcp.h xvm.h 

Log message:
	Add support for fence_xvm to RHEL4 branch (requires seamonkey-nss-devel and seamonkey-nspr-devel to compile)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/Makefile.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.5.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/README.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.1.6.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/TODO.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.2.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/debug.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.1.6.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/fence_xvm.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.4.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/ip_lookup.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.3.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/ip_lookup.h.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.1.6.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/mcast.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.2.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/mcast.h.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.1.6.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/options.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.4.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/options.h.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.2.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/simple_auth.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.3.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/simple_auth.h.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.1.6.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/tcp.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.2.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/tcp.h.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.1.6.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/xvm/xvm.h.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=NONE&r2=1.2.2.1

/cvs/cluster/cluster/fence/agents/xvm/Makefile,v  -->  standard output
revision 1.5.2.1
--- cluster/fence/agents/xvm/Makefile
+++ -	2006-12-01 15:49:39.073388000 +0000
@@ -0,0 +1,55 @@
+###############################################################################
+###############################################################################
+##
+##  Copyright (C) 2006 Red Hat, Inc.
+##  
+##  This copyrighted material is made available to anyone wishing to use,
+##  modify, copy, or redistribute it subject to the terms and conditions
+##  of the GNU General Public License v.2.
+##
+###############################################################################
+###############################################################################
+
+top_srcdir=../..
+include ${top_srcdir}/make/defines.mk
+
+TARGETS=fence_xvm
+
+fence_xvm_SOURCE = fence_xvm.c mcast.c ip_lookup.c simple_auth.c tcp.c \
+		   options.c debug.c
+
+#
+# RHEL4 branch notes!
+#
+# RHEL4 includes seamonkey-nss and seamonkey-nspr; we need both
+# seamonkey-nss-devel and seamonkey-nspr-devel to be installed in
+# order to build.  On RHEL4, these provide pkgconfig (note:
+# mozilla-config does not work) scripts to determine their
+# include locations.
+#
+INCLUDE=-I${top_srcdir}/include -I${top_srcdir}/config \
+	$(shell pkg-config --cflags mozilla-nss mozilla-nspr) \
+	-I../../../ccs/lib
+
+CFLAGS+=-DFENCE_RELEASE_NAME=\"${RELEASE}\" \
+	-Wall -Werror -Wstrict-prototypes -Wshadow -ggdb -D_GNU_SOURCE
+
+LIBS+=-L../../../ccs/lib -lnss3
+
+all: ${TARGETS}
+
+fence_xvm: ${fence_xvm_SOURCE:.c=.o}
+	gcc -o $@ $^ $(LIBS)
+
+%.o: %.c
+	gcc $(CFLAGS) -c -o $@ $^ $(INCLUDES)
+
+clean:
+	rm -f $(TARGETS) *~ *.o
+
+install: all
+	if [ ! -d ${sbindir} ]; then \
+		install -d ${sbindir}; \
+	fi
+	install -m755 ${TARGETS} ${sbindir}
+
/cvs/cluster/cluster/fence/agents/xvm/README,v  -->  standard output
revision 1.1.6.1
--- cluster/fence/agents/xvm/README
+++ -	2006-12-01 15:49:39.162701000 +0000
@@ -0,0 +1,182 @@
+I. Fence_xvm - virtual machine fencing agent
+
+Fence_xvm is an agent which establishes a communications link between
+a cluster of virtual machines (VC) and a cluster of domain0/physical
+nodes which are hosting the virtual cluster.  Its operations are
+fairly simple.
+
+  (a) Start a listener service.
+  (b) Send a multicast packet requesting that a VM be fenced.
+  (c) Authenticate client.
+  (e) Read response.
+  (f) Exit with success/failure, depending on the response received.
+
+If any of the above steps fail, the fencing agent exits with a failure
+code and fencing is retried by the virtual cluster at a later time.
+Because of the simplicty of fence_xvm, it is not necessary that
+fence_xvm be run from within a virtualized guest - all it needs is
+libnspr and libnss and a shared private key (for authentication; we
+would hate to receive a false positive response from a node not in the
+cluster!).
+
+
+II. Fence_xvmd - The virtual machine fencing host
+
+Fence_xvmd is a daemon which runs on physical hosts (e.g. in domain0)
+of the cluster hosting the virtual cluster.  It listens on a port
+for multicast traffic from virtual cluster(s), and takes actions.
+Multiple disjoint virtual clusters can coexist on a single physical
+host cluster, but this requires multiple instances of fence_xvmd.
+
+NOTE: fence_xvmd *MUST* be run on ALL nodes in a given cluster which
+will be hosting virtual machines if fence_xvm is to be used for 
+fencing!
+
+There are a couple of ways the multicast packet is handled,
+depending on the state of the host OS.  It might be hosting the VM,
+or it might not.  Furthermore, the VM might "reside" on a host which
+has failed.
+
+In order to be able to guarantee safe fencing of a VM even if the
+last- known host is down, we must store the last-known locations of
+each virtual machine in some sort of cluster-wide way.  For this, we
+use the AIS Checkpointing API, which is provided by OpenAIS.  Every
+few seconds, fence_xvmd queries the hypervisor via libvirt and
+stores any local VM states in a checkpoint.  In the event of a
+physical node failure (which consequently causes the failure of one
+or more guests), we can then read the checkpoint section corresponding
+to the guest we need to fence to find out the previous
+owner.  With that information, we can then check with CMAN to see if
+the last-known host node has been fenced.  If so, then the VM is
+clean as well.  The physical cluster must, therefore, have fencing
+in order for fence_xvmd to work.
+
+Operation of a node hosting a VM which needs to be fenced:
+  
+  (a) Receive multicast packet
+  (b) Authenticate multicast packet
+  (c) Open connection to host contained within multicast
+      packet.
+  (d) Authenticate server.
+  (e) Carry out fencing operation (e.g. call libvirt to destroy or
+      reboot the VM; there is no "on" method at this point).
+  (f) If operation succeeds, send success response.
+
+Operation of high-node-ID:
+
+  (a) Receive multicast packet
+  (b) Authenticate multicast packet
+  (c) Read VM state from checkpoint
+  (d) Check liveliness of nodeID hosting VM (if alive, do nothing)
+  (e) Open connection to host contained within multicast
+      packet.
+  (f) Check with CMAN to see if last-known host has been fenced.
+      (If it has not; do nothing -- this is why the physical 
+      cluster also needs fencing!)
+  (g) Authenticate server & send response.
+  (h) If last-known host has been fenced, send success response.
+
+NOTE: There is always a possibility that a VM is started again
+before the fencing operation and checkpoint update for that VM
+occurs.  If the VM has booted and rejoined the cluster, fencing will
+not be necessary.  If it is in the process of booting, but has not
+yet joined the cluster, fencing will also not be necessary - because
+it will not be using cluster resources yet.
+
+
+III. Security considerations
+
+While fencing is generally expected to run on a more or less trusted
+network, there are cases where it may not be.
+
+* The multicast packet is subject to replay attacks, but because no
+fencing action is taken based solely on the information contained
+within the packet, this should not allow an attacker to maliciously
+fence a VM from outside the cluster, though it may be possible to
+cause a DoS of fence_xvmd if enough multicast packets are sent.
+
+* The only currently supported authentication mechanisms are simple
+challenge-response based on a shared private key and pseudorandom
+number generation.
+
+* An attacker with access to the shared key(s) can easily fence any
+known VM, even if they are not on a cluster node.
+
+* Different shared keys should be used for different virtual
+clusters on the same subnet (whether in the same physical cluster
+or not).  Additionally, multiple fence_xvmd instances must be run
+(each listening on a different multicast IP + port combination).
+
+IV.  Configuration
+
+Generate a random key file.  An example of how to generate it is:
+
+    dd if=/dev/urandom of=/etc/cluster/fence_xvm.key bs=4096 count=1
+
+Distribute the generated key file to all virtual machines in a
+cluster as well as all physical host nodes which will be hosting
+that particular cluster of guests.  More simply, everything involved
+with hosting the virtual cluster as well as the virtual cluster
+itself must have the same key file; it acts as a password.
+
+The key should not be placed on shared file systems (because shared
+file systems require the cluster, which requires fencing...).  
+Furthermore, it is considered 'unsupported' to join a host cluster
+and a guest cluster in one management domain.
+
+A. Configuring the host (physical) cluster
+
+On the host cluster, you need to add the following tag as a
+child of the <cluster> tag in /etc/cluster/cluster.conf:
+
+    <fence_xvmd/>
+
+(Do not forget to increment the configuration version number and
+run 'ccs_tool update /etc/cluster/cluster.conf' !).
+
+Start fence_xvmd on all host nodes if it isn't already running.
+Just run 'fence_xvmd'.  The next time the cluster is restarted,
+fence_xvmd will start automatically; it is started by the cman
+script if you have the above tag in cluster.conf.
+
+B.  Configuring the guest (virtual) cluster
+
+On the guest cluster, you need to set up per-node fencing.  This
+is a fairly simple task as well.  First, you need to add a fence
+device for 'xvm'.  Simply add the following to the <fencedevices/>
+tag in the guest cluster's cluster.conf:
+
+    <fencedevice name="xvm" agent="fence_xvm"/>
+
+After doing this, each node also needs individual fencing set up.
+For each <clusternode/> tag, you will need to add something like
+the following:
+
+    <fence>
+        <method name="1">
+            <device name="xvm" domain="doman-name"/>
+        </method>
+    </fence>
+
+For example, if you have a virtual host named 'vm1.test.com' with a
+corresponding virtual domain name of 'domU-vm1' in the dom0 cluster,
+and a node ID of 1, the <clusternode> tag for that virtual machine
+would look like so:
+
+    <clusternode name="vm1.test.com" nodeid="1" votes="1">
+        <fence>
+            <method name="1">
+                <device name="xvm" domain="domU-vm1"/>
+            </method>
+        </fence>
+    </clusternode>
+
+C. Advanced configuration
+
+Any advanced configuration parameters (e.g. changing authentication,
+hashing, key file, etc.) should be included in the <fence_xvmd/> tag
+in the host cluster and the <fencedevice .../> tag in the guest
+cluster.  For a complete list of advanced parameters, see:
+
+    fence_xvmd -h
+    fence_xvm -h
/cvs/cluster/cluster/fence/agents/xvm/TODO,v  -->  standard output
revision 1.2.2.1
--- cluster/fence/agents/xvm/TODO
+++ -	2006-12-01 15:49:39.275150000 +0000
@@ -0,0 +1,33 @@
+High Priority / Blockers:
+
+* Nothing at this time.
+
+Medium Priority:
+
+* Need to add ability for fence_xvmd to forcefully fence the host
+dom0 if it's not responding.  Medium because it should not be the
+default behavior since fencing a host can affect multiple domains
+across potentially multiple domU clusters.  This will be a server-
+side configuration option; domUs will not be able to override it.
+
+* Support multiple authentication keys in fence_xvmd simultaneously
+so that we can fence multiple clusters with only one instance of
+fence_xvmd running on a given dom0.
+
+Low Priority:
+
+* Turn README in to man pages.
+
+* Make sure CMAN is running and/or restart/reconnect if CMAN goes
+away and comes back.  (If CMAN dies, we have big problems anyway)
+
+* Add SSL connection support.  (Challenge/response on a trusted
+network should be okay.)
+
+* Make sure addresses contained in the multicast packet are always
+in network-byte order.  Low because it will be unlikely that the
+host-byte ordering of a domU and its dom0 will be different.
+
+* Make sure node IDs and VM states stored in openais checkpoints
+are in network-byte order and swap back/forth if not.
+
/cvs/cluster/cluster/fence/agents/xvm/debug.c,v  -->  standard output
revision 1.1.6.1
--- cluster/fence/agents/xvm/debug.c
+++ -	2006-12-01 15:49:39.368367000 +0000
@@ -0,0 +1,34 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#include "xvm.h"
+
+static int _debug = 0;
+
+inline void
+dset(int threshold)
+{
+	_debug = threshold;
+	dprintf(3, "Debugging threshold is now %d\n", threshold);
+}
+
+inline int
+dget(void)
+{
+	return _debug;
+}
/cvs/cluster/cluster/fence/agents/xvm/fence_xvm.c,v  -->  standard output
revision 1.4.2.1
--- cluster/fence/agents/xvm/fence_xvm.c
+++ -	2006-12-01 15:49:39.470749000 +0000
@@ -0,0 +1,365 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+/*
+ * @file fence_xvmd.c: Implementation of server daemon for Xen virtual
+ * machine fencing.  This uses SA AIS CKPT b.1.0 checkpointing API to 
+ * store virtual machine states.
+ *
+ * Author: Lon Hohberger <lhh at redhat.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <libgen.h>
+#include <nss.h>
+
+/* Local includes */
+#include "xvm.h"
+#include "ip_lookup.h"
+#include "simple_auth.h"
+#include "options.h"
+#include "tcp.h"
+#include "mcast.h"
+
+
+int
+tcp_wait_connect(int lfd, int retry_tenths)
+{
+	int fd;
+	fd_set rfds;
+	int n;
+	struct timeval tv;
+
+	dprintf(3, "Waiting for connection from XVM host daemon.\n");
+	FD_ZERO(&rfds);
+	FD_SET(lfd, &rfds);
+	tv.tv_sec = retry_tenths / 10;
+	tv.tv_usec = (retry_tenths % 10) * 100000;
+
+	n = select(lfd + 1, &rfds, NULL, NULL, &tv);
+	if (n == 0) {
+		errno = ETIMEDOUT;
+		return -1;
+	} else if (n < 0) {
+		return -1;
+	}
+
+	fd = accept(lfd, NULL, 0);
+	if (fd < 0)
+		return -1;
+
+	return fd;
+}
+
+
+int
+tcp_exchange(int fd, fence_auth_type_t auth, void *key,
+	      size_t key_len, int timeout)
+{
+	char ret;
+	fd_set rfds;
+	struct timeval tv;
+
+	/* Ok, we're connected */
+	dprintf(3, "Issuing TCP challenge\n");
+	if (tcp_challenge(fd, auth, key, key_len, timeout) <= 0) {
+		/* Challenge failed */
+		printf("Invalid response to challenge\n");
+		return 0;
+	}
+
+	/* Now they'll send us one, so we need to respond here */
+	dprintf(3, "Responding to TCP challenge\n");
+	if (tcp_response(fd, auth, key, key_len, timeout) <= 0) {
+		printf("Invalid response to challenge\n");
+		return 0;
+	}
+
+	dprintf(2, "TCP Exchange + Authentication done... \n");
+
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+
+	ret = 1;
+	dprintf(3, "Waiting for return value from XVM host\n");
+	if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0)
+		return -1;
+
+	/* Read return code */
+	read(fd, &ret, 1);
+	close(fd);
+	if (ret == 0)
+		printf("Remote: Operation was successful\n");
+	else
+		printf("Remote: Operation failed\n");
+	return ret;
+}
+
+
+int
+send_multicast_packets(ip_list_t *ipl, fence_xvm_args_t *args, void *key,
+		       size_t key_len)
+{
+	fence_req_t freq;
+	int mc_sock;
+	ip_addr_t *ipa;
+	struct sockaddr_in tgt4;
+	struct sockaddr_in6 tgt6;
+	struct sockaddr *tgt;
+	socklen_t tgt_len;
+
+	for (ipa = ipl->tqh_first; ipa; ipa = ipa->ipa_entries.tqe_next) {
+
+		if (ipa->ipa_family != args->family) {
+			dprintf(2, "Ignoring %s: wrong family\n", ipa->ipa_address);
+			continue;
+		}
+
+		if (args->family == PF_INET) {
+			mc_sock = ipv4_send_sk(ipa->ipa_address, args->addr,
+					       args->port,
+					       (struct sockaddr *)&tgt4,
+					       sizeof(struct sockaddr_in));
+			tgt = (struct sockaddr *)&tgt4;
+			tgt_len = sizeof(tgt4);
+			
+		} else if (args->family == PF_INET6) {
+			mc_sock = ipv6_send_sk(ipa->ipa_address, args->addr,
+					       args->port,
+					       (struct sockaddr *)&tgt6,
+					       sizeof(struct sockaddr_in6));
+			tgt = (struct sockaddr *)&tgt6;
+			tgt_len = sizeof(tgt6);
+		} else {
+			dprintf(2, "Unsupported family %d\n", args->family);
+			return -1;
+		}
+
+		if (mc_sock < 0)
+			continue;
+
+		/* Build our packet */
+		memset(&freq, 0, sizeof(freq));
+		strncpy((char *)freq.domain, args->domain,
+			sizeof(freq.domain));
+		freq.request = args->op;
+		freq.hashtype = args->hash;
+
+		/* Store source address */
+		if (ipa->ipa_family == PF_INET) {
+			freq.addrlen = sizeof(struct in_addr);
+			/* XXX Swap order for in_addr ? XXX */
+			inet_pton(PF_INET, ipa->ipa_address, freq.address);
+		} else if (ipa->ipa_family == PF_INET6) {
+			freq.addrlen = sizeof(struct in6_addr);
+			inet_pton(PF_INET6, ipa->ipa_address, freq.address);
+		}
+
+		freq.flags = 0;
+		if (args->flags & F_USE_UUID)
+			freq.flags |= RF_UUID;
+		freq.family = ipa->ipa_family;
+		freq.port = args->port;
+
+		sign_request(&freq, key, key_len);
+
+		dprintf(3, "Sending to %s via %s\n", args->addr,
+		        ipa->ipa_address);
+
+		sendto(mc_sock, &freq, sizeof(freq), 0,
+		       (struct sockaddr *)tgt, tgt_len);
+
+		close(mc_sock);
+	}
+
+	return 0;
+}
+
+
+/* TODO: Clean this up!!! */
+int
+fence_xen_domain(fence_xvm_args_t *args)
+{
+	ip_list_t ipl;
+	char key[4096];
+	int lfd, key_len = 0, fd;
+	int attempts = 0;
+	
+	if (args->auth != AUTH_NONE || args->hash != HASH_NONE) {
+		key_len = read_key_file(args->key_file, key, sizeof(key));
+		if (key_len < 0) {
+			printf("Could not read key file\n");
+			return 1;
+		}
+	}
+
+	/* Do the real work */
+	if (ip_build_list(&ipl) < 0) {
+		printf("Error building IP address list\n");
+		return 1;
+	}
+
+	switch (args->auth) {
+		case AUTH_NONE:
+		case AUTH_SHA1:
+		case AUTH_SHA256:
+		case AUTH_SHA512:
+			if (args->family == PF_INET) {
+				lfd = ipv4_listen(args->port, 10);
+			} else {
+				lfd = ipv6_listen(args->port, 10);
+			}
+			break;
+		/*case AUTH_X509:*/
+			/* XXX Setup SSL listener socket here */
+		default:
+			return 1;
+	}
+
+	if (lfd < 0) {
+		printf("Failed to listen: %s\n", strerror(errno));
+		return 1;
+	}
+
+	attempts = args->timeout * 10 / args->retr_time;
+
+	do {
+		if (send_multicast_packets(&ipl, args, key, key_len)) {
+			return -1;
+		}
+
+		switch (args->auth) {
+			case AUTH_NONE:
+			case AUTH_SHA1:
+			case AUTH_SHA256:
+			case AUTH_SHA512:
+				fd = tcp_wait_connect(lfd, args->retr_time);
+				if (fd < 0 && (errno == ETIMEDOUT ||
+					       errno == EINTR))
+					continue;
+				break;
+			/* case AUTH_X509:
+				... = ssl_wait_connect... */
+			break;
+		default:
+			return 1;
+		}
+
+		break;
+	} while (--attempts);
+
+	if (fd < 0) {
+		if (attempts <= 0) {
+			printf("Timed out waiting for response\n");
+			return 1;
+		}
+		printf("Fencing failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	switch (args->auth) {
+		case AUTH_NONE:
+		case AUTH_SHA1:
+		case AUTH_SHA256:
+		case AUTH_SHA512:
+			return tcp_exchange(fd, args->auth, key, key_len,
+					    args->timeout);
+			break;
+		/* case AUTH_X509: 
+			return ssl_exchange(...); */
+		default:
+			return 1;
+	}
+
+	return 1;
+}
+
+
+int
+main(int argc, char **argv)
+{
+	fence_xvm_args_t args;
+	char *my_options = "di:a:p:r:C:c:k:H:uo:t:?hV";
+
+	args_init(&args);
+	if (argc == 1) {
+		args_get_stdin(my_options, &args);
+	} else {
+		args_get_getopt(argc, argv, my_options, &args);
+	}
+
+	if (args.flags & F_HELP) {
+		args_usage(argv[0], my_options, 0);
+		args_usage(argv[0], my_options, 1);
+		exit(0);
+	}
+
+	if (args.flags & F_VERSION) {
+		printf("%s %s\n", basename(argv[0]), XVM_VERSION);
+#ifdef FENCE_RELEASE_NAME
+		printf("fence release %s\n", FENCE_RELEASE_NAME);
+#endif
+		exit(0);
+	}
+
+	args_finalize(&args);
+	dset(args.debug);
+	
+	if (args.debug > 0) 
+		args_print(&args);
+
+	/* Additional validation here */
+	if (!args.domain) {
+		printf("No domain specified!\n");
+		args.flags |= F_ERR;
+	}
+
+	if (args.flags & F_ERR) {
+		args_usage(argv[0], my_options, (argc == 1));
+		exit(1);
+	}
+
+	/* Initialize NSS; required to do hashing, as silly as that
+	   sounds... */
+	if (NSS_NoDB_Init(NULL) != SECSuccess) {
+		printf("Could not initialize NSS\n");
+		return 1;
+	}
+
+	return fence_xen_domain(&args);
+}
/cvs/cluster/cluster/fence/agents/xvm/ip_lookup.c,v  -->  standard output
revision 1.3.2.1
--- cluster/fence/agents/xvm/ip_lookup.c
+++ -	2006-12-01 15:49:39.592613000 +0000
@@ -0,0 +1,321 @@
+/*
+  Copyright Red Hat, Inc. 2004, 2006
+
+  The Magma Cluster API Library is free software; you can redistribute
+  it and/or modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either version
+  2.1 of the License, or (at your option) any later version.
+
+  The Magma Cluster API Library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+ */
+/** @file
+ * Build lists of IPs on the system, excepting loopback ipv6 link-local
+ */
+#include <asm/types.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+
+#ifndef IFA_MAX
+#include <linux/if_addr.h>
+#endif
+
+/* Local includes */
+#include "ip_lookup.h"
+
+static int
+send_addr_dump(int fd, int family)
+{
+	struct nlmsghdr *nh;
+	struct rtgenmsg *g;
+	char buf[256];
+	struct sockaddr_nl addr;
+
+	memset(&addr,0,sizeof(addr));
+	addr.nl_family = PF_NETLINK;
+
+	memset(buf, 0, sizeof(buf));
+	nh = (struct nlmsghdr *)buf;
+	g = (struct rtgenmsg *)(buf + sizeof(struct nlmsghdr));
+
+	nh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+	nh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+	nh->nlmsg_type = RTM_GETADDR;
+	g->rtgen_family = family;
+
+	return sendto(fd, buf, nh->nlmsg_len, 0, (struct sockaddr *)&addr,
+	   	      sizeof(addr));
+}
+
+
+static int
+add_ip(ip_list_t *ipl, char *ipaddr, char family)
+{
+	ip_addr_t *ipa;
+
+	if (family == PF_INET6) {
+		/* Avoid loopback */
+		if (!strcmp(ipaddr, "::1"))
+			return -1;
+
+		/* Avoid link-local addresses */
+		if (!strncmp(ipaddr, "fe80", 4))
+			return -1;
+		if (!strncmp(ipaddr, "fe90", 4))
+			return -1;
+		if (!strncmp(ipaddr, "fea0", 4))
+			return -1;
+		if (!strncmp(ipaddr, "feb0", 4))
+			return -1;
+	}
+	
+	dprintf(4, "Adding IP %s to list (family %d)\n", ipaddr, family);
+
+	ipa = malloc(sizeof(*ipa));
+	memset(ipa, 0, sizeof(*ipa));
+	ipa->ipa_family = family;
+	ipa->ipa_address = strdup(ipaddr);
+
+	TAILQ_INSERT_TAIL(ipl, ipa, ipa_entries);
+
+	return 0;
+}
+
+
+static int
+add_ip_addresses(int family, ip_list_t *ipl)
+{
+	/* List ipv4 addresses */
+	struct nlmsghdr *nh;
+	struct ifaddrmsg *ifa;
+	struct rtattr *rta, *nrta;
+	struct nlmsgerr *err;
+	char buf[10240];
+	char outbuf[256];
+	int x, fd, len;
+
+	dprintf(5, "Connecting to Netlink...\n");
+	fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+	if (fd < 0) {
+		perror("socket");
+		exit(1);
+	}
+	
+	dprintf(5, "Sending address dump request\n");
+	send_addr_dump(fd, family);
+	memset(buf, 0, sizeof(buf));
+	
+	dprintf(5, "Waiting for response\n");
+	x = recvfrom(fd, buf, sizeof(buf), 0, NULL, 0);
+	if (x < 0) {
+		perror("recvfrom");
+		return -1;
+	}
+	
+	dprintf(5, "Received %d bytes\n", x);
+
+	nh = (struct nlmsghdr *)buf;
+	while (NLMSG_OK(nh, x)) {
+
+		switch(nh->nlmsg_type) {
+		case NLMSG_DONE:
+			close(fd);
+    			return 0;
+
+		case NLMSG_ERROR:
+			err = (struct nlmsgerr*)NLMSG_DATA(nh);
+			if (nh->nlmsg_len <
+			    NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+				fprintf(stderr, "ERROR truncated");
+			} else {
+				errno = -err->error;
+				perror("RTNETLINK answers");
+			}
+			close(fd);
+			return -1;
+
+		case RTM_NEWADDR:
+			break;
+
+		default:
+			nh = NLMSG_NEXT(nh, x);
+			continue;
+		}
+
+		/* RTM_NEWADDR */
+		len = NLMSG_PAYLOAD(nh,0);
+		ifa = NLMSG_DATA(nh);
+
+		/* Make sure we got the type we expect back */
+		if (ifa->ifa_family != family) {
+			nh = NLMSG_NEXT(nh, x);
+			continue;
+		}
+
+		rta = (struct rtattr *)((void *)ifa + sizeof(*ifa));
+		len -= sizeof(*ifa);
+		do {
+			/* Make sure we've got a valid rtaddr field */
+			if (!RTA_OK(rta, len)) {
+				dprintf(5, "!RTA_OK(rta, len)\n");
+				break;
+			}
+
+			if (rta->rta_type == IFA_ADDRESS) {
+				inet_ntop(family, RTA_DATA(rta), outbuf,
+					  sizeof(outbuf) );
+				add_ip(ipl, outbuf, family);
+			}
+
+			if (rta->rta_type == IFA_LABEL) {
+				dprintf(5, "Skipping label: %s\n",
+					(char *)RTA_DATA(rta));
+			}
+
+			nrta = RTA_NEXT(rta, len);
+			if (!nrta)
+				break;
+
+			len -= ((void *)nrta - (void *)rta);
+			rta = nrta;
+		} while (RTA_OK(rta, len));
+
+		nh = NLMSG_NEXT(nh, x);
+	}
+
+	dprintf(5, "Closing Netlink connection\n");
+	close(fd);
+	return 0;
+}
+
+
+int
+ip_search(ip_list_t *ipl, char *ip_name)
+{
+	ip_addr_t *ipa;
+	
+	dprintf(5, "Looking for IP address %s in IP list %p...", ip_name, ipl);
+	ipa = ipl->tqh_first;
+	for (ipa = ipl->tqh_first; ipa; ipa = ipa->ipa_entries.tqe_next) {
+		if (!strcmp(ip_name, ipa->ipa_address)) {
+			dprintf(4,"Found\n");
+			return 0;
+		}
+	}
+	dprintf(5, "Not found\n");
+	return 1;
+}
+
+
+int
+ip_free_list(ip_list_t *ipl)
+{
+	ip_addr_t *ipa;
+	
+	dprintf(5, "Tearing down IP list @ %p\n", ipl);
+	while ((ipa = ipl->tqh_first)) {
+		TAILQ_REMOVE(ipl, ipa, ipa_entries);
+		free(ipa->ipa_address);
+		free(ipa);
+	}
+	return 0;
+}
+
+
+int
+ip_build_list(ip_list_t *ipl)
+{
+	dprintf(5, "Build IP address list\n");
+	TAILQ_INIT(ipl);
+	if (add_ip_addresses(PF_INET6, ipl) < 0) {
+		ip_free_list(ipl);
+		return -1;
+	}
+	if (add_ip_addresses(PF_INET, ipl) < 0) {
+		ip_free_list(ipl);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+  Look up the interface name which corresponds to the given hostname and
+  return the list of matching attrinfo structures.  We do this by looking
+  up all the possible physical and virtual network interfaces on the machine
+  and checking the hostname/IP mappings for each active IP address incurred.
+
+  @param nodename	Interface name
+  @param ret_ai		Structure pointer to allocate & return.
+  @return		-1 on failure or 0 on success.
+ */
+int
+ip_lookup(char *nodename, struct addrinfo **ret_ai)
+{
+	char ip_name[256];
+	struct addrinfo *ai = NULL;
+	struct addrinfo *n;
+	void *p;
+	ip_list_t ipl;
+	int ret = -1;
+
+	dprintf(5, "Looking for IP matching %s\n", nodename);
+	/* Build list of IP addresses configured locally */
+	if (ip_build_list(&ipl) < 0)
+		return -1;
+
+	/* Get list of addresses for the host-name/ip */
+	if (getaddrinfo(nodename, NULL, NULL, &ai) != 0) 
+		return -1;
+	
+
+	/* Traverse list of addresses for given host-name/ip */
+	for (n = ai; n; n = n->ai_next) {
+		if (n->ai_family != PF_INET && n->ai_family != PF_INET6)
+			continue;
+
+		if (n->ai_family == PF_INET)
+			p = &(((struct sockaddr_in *)n->ai_addr)->sin_addr);
+		else
+			p = &(((struct sockaddr_in6 *)n->ai_addr)->sin6_addr);
+
+		if (!inet_ntop(n->ai_family, p, ip_name,
+			       sizeof(ip_name)))
+			continue;
+
+		/* Search local interfaces for this IP address */
+		if (ip_search(&ipl, ip_name) != 0)
+			continue;
+
+		/* Found it */
+		ret = 0;
+		break;
+	}
+
+	/* Clean up */
+	if (!ret_ai)
+		freeaddrinfo(ai);
+	else
+		*ret_ai = ai;
+
+	ip_free_list(&ipl);
+
+	return ret;
+}
+
/cvs/cluster/cluster/fence/agents/xvm/ip_lookup.h,v  -->  standard output
revision 1.1.6.1
--- cluster/fence/agents/xvm/ip_lookup.h
+++ -	2006-12-01 15:49:39.682836000 +0000
@@ -0,0 +1,40 @@
+/*
+  Copyright Red Hat, Inc. 2004,2006
+
+  The Magma Cluster API Library is free software; you can redistribute
+  it and/or modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either version
+  2.1 of the License, or (at your option) any later version.
+
+  The Magma Cluster API Library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+*/
+/** @file
+ * Header for ip_lookup.c
+ */
+#ifndef _IP_LOOKUP_H
+#define _IP_LOOKUP_H
+
+#include <sys/queue.h>
+
+typedef struct _ip_address {
+	TAILQ_ENTRY(_ip_address) ipa_entries;
+	char ipa_family;
+	char *ipa_address;
+} ip_addr_t;
+
+typedef TAILQ_HEAD(_ip_list, _ip_address) ip_list_t;
+
+int ip_search(ip_list_t *ipl, char *ip_name);
+int ip_free_list(ip_list_t *ipl);
+int ip_build_list(ip_list_t *ipl);
+int ip_lookup(char *, struct addrinfo **);
+
+#endif
/cvs/cluster/cluster/fence/agents/xvm/mcast.c,v  -->  standard output
revision 1.2.2.1
--- cluster/fence/agents/xvm/mcast.c
+++ -	2006-12-01 15:49:39.781466000 +0000
@@ -0,0 +1,372 @@
+/*
+  Copyright Red Hat, Inc. 2003, 2004, 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+/*
+ * Author: Lon Hohberger <lhh at redhat.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+
+/* Local includes */
+#include "mcast.h"
+
+/** 
+  Sets up a multicast receive socket
+ */
+int
+ipv4_recv_sk(char *addr, int port)
+{
+	int sock;
+	struct ip_mreq mreq;
+	struct sockaddr_in sin;
+
+	/* Store multicast address */
+	if (inet_pton(PF_INET, addr,
+		      (void *)&mreq.imr_multiaddr.s_addr) < 0) {
+		printf("Invalid multicast address: %s\n", addr);
+		return -1;
+	}
+
+	/********************************
+	 * SET UP MULTICAST RECV SOCKET *
+	 ********************************/
+	dprintf(4, "Setting up ipv4 multicast receive (%s:%d)\n", addr, port);
+	sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		printf("socket: %s\n", strerror(errno));
+		close(sock);
+		sock = -1;
+		return 1;
+	}
+
+	/*
+	 * When using Multicast, bind to the LOCAL address, not the MULTICAST
+	 * address.
+	 */
+	sin.sin_family = PF_INET;
+	sin.sin_port = htons(port);
+	sin.sin_addr.s_addr = htonl(INADDR_ANY);
+	if (bind(sock, (struct sockaddr *) &sin,
+		 sizeof(struct sockaddr_in)) < 0) {
+		printf("bind failed: %s\n", strerror(errno));
+		close(sock);
+		return -1;
+	}
+
+	/*
+	 * Join multicast group
+	 */
+	/* mreq.imr_multiaddr.s_addr is set above */
+	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+	dprintf(4, "Joining multicast group\n");
+	if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+		       &mreq, sizeof(mreq)) == -1) {
+		printf("Failed to bind multicast receive socket to "
+		       "%s: %s\n", addr, strerror(errno));
+		printf("Check network configuration.\n");
+		close(sock);
+		return -1;
+	}
+
+	dprintf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
+	return sock;
+}
+
+
+/**
+  Set up multicast send socket
+ */
+int
+ipv4_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt,
+	     socklen_t tgt_len)
+{
+	int val;
+	struct ip_mreq mreq;
+	struct sockaddr_in mcast;
+	struct sockaddr_in src;
+	int sock;
+
+	if (tgt_len < sizeof(struct sockaddr_in)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Store multicast address */
+	mcast.sin_family = PF_INET;
+	mcast.sin_port = htons(port);
+	if (inet_pton(PF_INET, addr,
+		      (void *)&mcast.sin_addr.s_addr) < 0) {
+		printf("Invalid multicast address: %s\n", addr);
+		return -1;
+	}
+	mreq.imr_multiaddr.s_addr = mcast.sin_addr.s_addr;
+
+	/* Store sending address */
+	src.sin_family = PF_INET;
+	src.sin_port = htons(port);
+	if (inet_pton(PF_INET, send_addr,
+		      (void *)&src.sin_addr.s_addr) < 0) {
+		printf("Invalid source address: %s\n", send_addr);
+		return -1;
+	}
+	mreq.imr_interface.s_addr = src.sin_addr.s_addr;
+
+
+	/*************************
+	 * SET UP MULTICAST SEND *
+	 *************************/
+	dprintf(4, "Setting up ipv4 multicast send (%s:%d)\n", addr, port);
+	sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	/*
+	 * Join Multicast group.
+	 */
+	dprintf(4, "Joining IP Multicast group (pass 1)\n");
+	if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
+		       sizeof(mreq)) == -1) {
+		printf("Failed to add multicast membership to transmit "
+		       "socket %s: %s\n", addr, strerror(errno));
+		close(sock);
+		return -1;
+	}
+
+	/*
+	 * Join Multicast group.
+	 */
+	dprintf(4, "Joining IP Multicast group (pass 2)\n");
+	if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &src.sin_addr,
+		       sizeof(src.sin_addr)) == -1) {
+		printf("Failed to bind multicast transmit socket to "
+		       "%s: %s\n", addr, strerror(errno));
+		close(sock);
+		return -1;
+	}
+
+	/*
+	 * set time to live to 2 hops.
+	 */
+	dprintf(4, "Setting TTL to 2 for fd%d\n", sock);
+	val = 2;
+	if (setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &val,
+		       sizeof(val)))
+		printf("warning: setting TTL failed %s\n", strerror(errno));
+
+	memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in));
+
+	dprintf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
+	return sock;
+}
+
+
+
+/** 
+  Sets up a multicast receive (ipv6) socket
+ */
+int
+ipv6_recv_sk(char *addr, int port)
+{
+	int sock, val;
+	struct ipv6_mreq mreq;
+	struct sockaddr_in6 sin;
+
+	memset(&mreq, 0, sizeof(mreq));
+	memset(&sin, 0, sizeof(sin));
+	sin.sin6_family = PF_INET6;
+	sin.sin6_port = htons(port);
+	if (inet_pton(PF_INET6, addr,
+		      (void *)&sin.sin6_addr) < 0) {
+		printf("Invalid multicast address: %s\n", addr);
+		return -1;
+	}
+
+	memcpy(&mreq.ipv6mr_multiaddr, &sin.sin6_addr,
+	       sizeof(struct in6_addr));
+
+
+	/********************************
+	 * SET UP MULTICAST RECV SOCKET *
+	 ********************************/
+	dprintf(4, "Setting up ipv6 multicast receive (%s:%d)\n", addr, port);
+	sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+	if (sock < 0) {
+		printf("socket: %s\n", strerror(errno));
+		close(sock);
+		sock = -1;
+		return 1;
+	}
+
+	/*
+	 * When using Multicast, bind to the LOCAL address, not the MULTICAST
+	 * address.
+	 */
+	memset(&sin, 0, sizeof(sin));
+	sin.sin6_family = PF_INET6;
+	sin.sin6_port = htons(port);
+	sin.sin6_addr = in6addr_any;
+	if (bind(sock, (struct sockaddr *) &sin,
+		 sizeof(struct sockaddr_in6)) < 0) {
+		printf("bind failed: %s\n", strerror(errno));
+		close(sock);
+		return -1;
+	}
+
+	dprintf(4, "Disabling IP Multicast loopback\n");
+	val = 1;
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+		       sizeof(val)) != 0) {
+		printf("Failed to disable multicast loopback\n");
+		close(sock);
+		return -1;
+	}
+
+	/*
+	 * Join multicast group
+	 */
+	dprintf(4, "Joining IP Multicast group\n");
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
+		       sizeof(mreq)) == -1) {
+		printf("Failed to add multicast to socket %s: %s\n",
+		       addr, strerror(errno));
+		close(sock);
+		return -1;
+	}
+
+	dprintf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
+	return sock;
+}
+
+
+/**
+  Set up ipv6 multicast send socket
+ */
+int
+ipv6_send_sk(char *send_addr, char *addr, int port, struct sockaddr *tgt,
+	     socklen_t tgt_len)
+{
+	int val;
+	struct ipv6_mreq mreq;
+	struct sockaddr_in6 mcast;
+	struct sockaddr_in6 src;
+	int sock;
+
+	if (tgt_len < sizeof(struct sockaddr_in6)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	memset(&mreq, 0, sizeof(mreq));
+
+	/* Store multicast address */
+	mcast.sin6_family = PF_INET6;
+	mcast.sin6_port = htons(port);
+	if (inet_pton(PF_INET6, addr,
+		      (void *)&mcast.sin6_addr) < 0) {
+		printf("Invalid multicast address: %s\n", addr);
+		return -1;
+	}
+
+	memcpy(&mreq.ipv6mr_multiaddr, &mcast.sin6_addr,
+	       sizeof(struct in6_addr));
+
+	/* Store sending address */
+	src.sin6_family = PF_INET6;
+	src.sin6_port = htons(port);
+	if (inet_pton(PF_INET6, send_addr,
+		      (void *)&src.sin6_addr) < 0) {
+		printf("Invalid source address: %s\n", send_addr);
+		return -1;
+	}
+
+	/*************************
+	 * SET UP MULTICAST SEND *
+	 *************************/
+	dprintf(4, "Setting up ipv6 multicast send (%s:%d)\n", addr, port);
+	sock = socket(PF_INET6, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	dprintf(4, "Disabling IP Multicast loopback\n");
+	val = 1;
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+		       sizeof(val)) != 0) {
+		printf("Failed to disable multicast loopback\n");
+		close(sock);
+		return -1;
+	}
+
+	/*
+	 * Join Multicast group.
+	 */
+	dprintf(4, "Joining IP Multicast group\n");
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
+		       sizeof(mreq)) == -1) {
+		printf("Failed to add multicast membership to transmit "
+		       "socket %s: %s\n", addr, strerror(errno));
+		close(sock);
+		return -1;
+	}
+
+	/*
+	 * Join Multicast group (part 2)
+	 */
+	/*
+	if (setsockopt(sock, IPPROTO_IPV6, IP_MULTICAST_IF, &src.sin6_addr,
+		       sizeof(src.sin6_addr)) == -1) {
+		printf("Failed to bind multicast transmit socket to "
+		       "%s: %s\n", addr, strerror(errno));
+		close(sock);
+		return -1;
+	}
+	*/
+
+	/*
+	 * set time to live to 2 hops.
+	 */
+	val = 2;
+	if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
+		       sizeof(val)))
+		printf("warning: setting TTL failed %s\n", strerror(errno));
+
+	memcpy((struct sockaddr_in *)tgt, &mcast, sizeof(struct sockaddr_in6));
+
+	dprintf(4, "%s: success, fd = %d\n", __FUNCTION__, sock);
+	return sock;
+}
/cvs/cluster/cluster/fence/agents/xvm/mcast.h,v  -->  standard output
revision 1.1.6.1
--- cluster/fence/agents/xvm/mcast.h
+++ -	2006-12-01 15:49:39.917288000 +0000
@@ -0,0 +1,32 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#ifndef _XVM_MCAST_H
+#define _XVM_MCAST_H
+
+#define IPV4_MCAST_DEFAULT "225.0.0.12"
+#define IPV6_MCAST_DEFAULT "ff05::3:1"
+
+int ipv4_recv_sk(char *addr, int port);
+int ipv4_send_sk(char *src_addr, char *addr, int port,
+		 struct sockaddr *src, socklen_t slen);
+int ipv6_recv_sk(char *addr, int port);
+int ipv6_send_sk(char *src_addr, char *addr, int port,
+		 struct sockaddr *src, socklen_t slen);
+
+#endif
/cvs/cluster/cluster/fence/agents/xvm/options.c,v  -->  standard output
revision 1.4.2.1
--- cluster/fence/agents/xvm/options.c
+++ -	2006-12-01 15:49:40.071321000 +0000
@@ -0,0 +1,637 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Local includes */
+#include "xvm.h"
+#include "simple_auth.h"
+#include "mcast.h"
+#include "options.h"
+
+
+
+/* Assignment functions */
+
+static inline void
+assign_debug(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	if (!value) {
+		/* GNU getopt sets optarg to NULL for options w/o a param
+		   We rely on this here... */
+		args->debug++;
+		return;
+	}
+
+	args->debug = atoi(value);
+	if (args->debug < 0) {
+		args->debug = 1;
+	}
+}
+
+
+static inline void
+assign_foreground(fence_xvm_args_t *args, struct arg_info *arg,
+		  char *value)
+{
+	args->flags |= F_FOREGROUND;
+}
+
+
+static inline void
+assign_family(fence_xvm_args_t *args, struct arg_info *arg,
+	      char *value)
+{
+	if (!strcasecmp(value, "ipv4")) {
+		args->family = PF_INET;
+	} else if (!strcasecmp(value, "ipv6")) {
+		args->family = PF_INET6;
+	} else if (!strcasecmp(value, "auto")) {
+		args->family = 0;
+	} else {
+		printf("Unsupported family: '%s'\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_address(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->addr = strdup(value);
+}
+
+
+static inline void
+assign_port(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->port = atoi(value);
+	if (args->port <= 0 || args->port >= 65500) {
+		printf("Invalid port: '%s'\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_retrans(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->retr_time = atoi(value);
+	if (args->retr_time <= 0) {
+		printf("Invalid retransmit time: '%s'\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+static inline void
+assign_hash(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	if (!strcasecmp(value, "none")) {
+		args->hash = HASH_NONE;
+	} else if (!strcasecmp(value, "sha1")) {
+		args->hash = HASH_SHA1;
+	} else if (!strcasecmp(value, "sha256")) {
+		args->hash = HASH_SHA256;
+	} else if (!strcasecmp(value, "sha512")) {
+		args->hash = HASH_SHA512;
+	} else {
+		printf("Unsupported hash: %s\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_auth(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	if (!strcasecmp(value, "none")) {
+		args->auth = AUTH_NONE;
+	} else if (!strcasecmp(value, "sha1")) {
+		args->auth = AUTH_SHA1;
+	} else if (!strcasecmp(value, "sha256")) {
+		args->auth = AUTH_SHA256;
+	} else if (!strcasecmp(value, "sha512")) {
+		args->auth = AUTH_SHA512;
+	} else {
+		printf("Unsupported auth type: %s\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+static inline void
+assign_key(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	struct stat st;
+
+	args->key_file = strdup(value);
+
+	if (stat(value, &st) == -1) {
+		printf("Invalid key file: '%s' (%s)\n", value,
+		       strerror(errno));
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_op(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	if (!strcasecmp(value, "null")) {
+		args->op = FENCE_NULL;
+	} else if (!strcasecmp(value, "off")) {
+		args->op = FENCE_OFF;
+	} else if (!strcasecmp(value, "reboot")) {
+		args->op = FENCE_REBOOT;
+	} else {
+		printf("Unsupported operation: %s\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_domain(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	if (args->domain) {
+		printf("Domain/UUID may not be specified more than once\n");
+		args->flags |= F_ERR;
+		return;
+	}
+
+	args->domain = strdup(value);
+
+	if (strlen(value) <= 0) {
+		printf("Invalid domain name\n");
+		args->flags |= F_ERR;
+	}
+
+	if (strlen(value) >= MAX_DOMAINNAME_LENGTH) {
+		errno = ENAMETOOLONG;
+		printf("Invalid domain name: '%s' (%s)\n",
+		       value, strerror(errno));
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_uuid_lookup(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	if (!value) {
+		/* GNU getopt sets optarg to NULL for options w/o a param
+		   We rely on this here... */
+		args->flags |= F_USE_UUID;
+		return;
+	}
+
+	args->flags |= ( !!atoi(value) ? F_USE_UUID : 0);
+}
+
+
+static inline void
+assign_timeout(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->timeout = atoi(value);
+	if (args->timeout <= 0) {
+		printf("Invalid timeout: '%s'\n", value);
+		args->flags |= F_ERR;
+	}
+}
+
+
+static inline void
+assign_help(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->flags |= F_HELP;
+}
+
+
+static inline void
+assign_version(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->flags |= F_VERSION;
+}
+
+
+static inline void
+assign_noccs(fence_xvm_args_t *args, struct arg_info *arg, char *value)
+{
+	args->flags |= F_NOCCS;
+}
+
+
+/** ALL valid command line and stdin arguments for this fencing agent */
+static struct arg_info _arg_info[] = {
+	{ '\xff', NULL, "agent",
+	  "Not user serviceable",
+	  NULL },
+
+	{ '\xff', NULL, "self",
+	  "Not user serviceable", 
+	  NULL },
+
+	{ 'd', "-d", "debug",
+	  "Enable debugging mode",
+	  assign_debug },
+
+	{ 'f', "-f", NULL,
+	  "Foreground mode (do not fork)",
+	  assign_foreground },
+
+	{ 'i', "-i <family>", "ip_family",
+	  "IP Family ([auto], ipv4, ipv6)",
+	  assign_family },
+
+	{ 'a', "-a <address>", "multicast_address",
+	  "Multicast address (default=225.0.0.12 / ff02::3:1)",
+	  assign_address },
+
+	{ 'p', "-p <port>", "port",
+	  "IP port (default=1229)",
+	  assign_port },
+
+	{ 'r', "-r <retrans>", "retrans", 
+	  "Multicast retransmit time (in 1/10sec; default=20)",
+	  assign_retrans },
+
+	{ 'c', "-c <hash>", "hash",
+	  "Packet hash strength (none, sha1, [sha256], sha512)",
+	  assign_hash },
+
+	{ 'C', "-C <auth>", "auth",
+	  "Authentication (none, sha1, [sha256], sha512)",
+	  assign_auth },
+
+	{ 'k', "-k <file>", "key_file",
+	  "Shared key file (default=/etc/cluster/fence_xvm.key)",
+	  assign_key },
+
+	{ 'o', "-o <operation>", "option",
+	  "Fencing operation (null, off, [reboot])",
+	  assign_op },
+
+	{ 'H', "-H <domain>", "domain",
+	  "Xen host (domain name) to fence",
+	  assign_domain },
+
+	{ 'u', "-u", "use_uuid",
+	  "Treat <domain> as UUID instead of domain name",
+	  assign_uuid_lookup },
+
+	{ 't', "-t <timeout>", "timeout",
+	  "Fencing timeout (in seconds; default=30)",
+	  assign_timeout },
+
+	{ 'h', "-h", NULL,
+ 	  "Help",
+	  assign_help },
+
+	{ '?', "-?", NULL,
+ 	  "Help (alternate)", 
+	  assign_help },
+
+	{ 'X', "-X", NULL,
+ 	  "Do not connect to CCS for configuration", 
+	  assign_noccs }, 
+	  
+	{ 'V', "-V", NULL,
+ 	  "Display version and exit", 
+	  assign_version },
+
+	/* Terminator */
+	{ 0, NULL, NULL, NULL, NULL }
+};
+
+
+struct arg_info *
+find_arg_by_char(char arg)
+{
+	int x = 0;
+
+	for (x = 0; _arg_info[x].opt != 0; x++) {
+		if (_arg_info[x].opt == arg)
+			return &_arg_info[x];
+	}
+
+	return NULL;
+}
+
+
+struct arg_info *
+find_arg_by_string(char *arg)
+{
+	int x = 0;
+
+	for (x = 0; _arg_info[x].opt != 0; x++) {
+		if (!_arg_info[x].stdin_opt)
+			continue;
+		if (!strcasecmp(_arg_info[x].stdin_opt, arg))
+			return &_arg_info[x];
+	}
+
+	return NULL;
+}
+
+
+/* ============================================================= */
+
+/**
+  Initialize an args structure.
+
+  @param args		Pointer to args structure to initialize.
+ */
+void
+args_init(fence_xvm_args_t *args)
+{
+	args->addr = NULL;
+	args->domain = NULL;
+	args->key_file = DEFAULT_KEY_FILE;
+	args->op = FENCE_REBOOT;
+	args->hash = DEFAULT_HASH;
+	args->auth = DEFAULT_AUTH;
+	args->port = 1229;
+	args->family = PF_INET;
+	args->timeout = 30;
+	args->retr_time = 20;
+	args->flags = 0;
+	args->debug = 0;
+}
+
+
+#define _pr_int(piece) printf("  %s = %d\n", #piece, piece)
+#define _pr_str(piece) printf("  %s = %s\n", #piece, piece)
+
+
+/**
+  Prints out the contents of an args structure for debugging.
+
+  @param args		Pointer to args structure to print out.
+ */
+void
+args_print(fence_xvm_args_t *args)
+{
+	printf("-- args @ %p --\n", args);
+	_pr_str(args->addr);
+	_pr_str(args->domain);
+	_pr_str(args->key_file);
+	_pr_int(args->op);
+	_pr_int(args->hash);
+	_pr_int(args->auth);
+	_pr_int(args->port);
+	_pr_int(args->family);
+	_pr_int(args->timeout);
+	_pr_int(args->retr_time);
+	_pr_int(args->flags);
+	_pr_int(args->debug);
+	printf("-- end args --\n");
+}
+
+
+/**
+  Print out arguments and help information based on what is allowed in
+  the getopt string optstr.
+
+  @param progname	Program name.
+  @param optstr		Getopt(3) style options string
+  @param print_stdin	0 = print command line options + description,
+			1 = print fence-style stdin args + description
+ */
+void
+args_usage(char *progname, char *optstr, int print_stdin)
+{
+	int x;
+	struct arg_info *arg;
+
+	if (print_stdin) {
+		printf("With no command line argument, arguments are "
+		       "read from standard input.\n");
+		printf("Arguments read from standard input take "
+		       "the form of:\n\n");
+		printf("    arg1=value1\n");
+		printf("    arg2=value2\n\n");
+	} else {
+		if (progname) {
+			printf("usage: %s [args]\n", progname);
+		} else {
+			printf("usage: fence_xvm [args]\n");
+		}
+	}
+
+	for (x = 0; x < strlen(optstr); x++) {
+		arg = find_arg_by_char(optstr[x]);
+		if (!arg)
+			continue;
+
+		if (print_stdin) {
+			if (arg && arg->stdin_opt)
+				printf("  %-20.20s %-55.55s\n",
+				       arg->stdin_opt, arg->desc);
+		} else {
+			printf("  %-20.20s %-55.55s\n", arg->opt_desc,
+			       arg->desc);
+		}
+	}
+
+	printf("\n");
+}
+
+
+/**
+  Remove leading and trailing whitespace from a line of text.
+
+  @param line		Line to clean up
+  @param linelen	Max size of line
+  @return		0 on success, -1 on failure
+ */
+int
+cleanup(char *line, size_t linelen)
+{
+	char *p;
+	int x;
+	
+	/* Remove leading whitespace. */
+	p = line;
+	for (x = 0; x <= linelen; x++) {
+		switch (line[x]) {
+		case '\t':
+		case ' ':
+			break;
+		case '\n':
+		case '\r':
+			return -1;
+		default:
+			goto eol;
+		}
+	}
+eol:
+	/* Move the remainder down by as many whitespace chars as we
+	   chewed up */
+	if (x)
+		memmove(p, &line[x], linelen-x);
+
+	/* Remove trailing whitespace. */
+	for (x=0; x <= linelen; x++) {
+		switch(line[x]) {
+		case '\t':
+		case ' ':
+		case '\r':
+		case '\n':
+			line[x] = 0;
+		case 0:
+		/* End of line */
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+/**
+  Parse args from stdin and assign to the specified args structure.
+  
+  @param optstr		Command line option string in getopt(3) format
+  @param args		Args structure to fill in.
+ */
+void
+args_get_stdin(char *optstr, fence_xvm_args_t *args)
+{
+	char in[256];
+	int line = 0;
+	char *name, *val;
+	struct arg_info *arg;
+
+	while (fgets(in, sizeof(in), stdin)) {
+		++line;
+
+		if (in[0] == '#')
+			continue;
+
+		if (cleanup(in, sizeof(in)) == -1)
+			continue;
+
+		name = in;
+		if ((val = strchr(in, '='))) {
+			*val = 0;
+			++val;
+		}
+
+		arg = find_arg_by_string(name);
+		if (!arg || (arg->opt != '\xff' && 
+			     !strchr(optstr, arg->opt))) {
+			fprintf(stderr,
+				"parse warning: "
+				"illegal variable '%s' on line %d\n", name,
+				line);
+			continue;
+		}
+
+		if (arg->assign)
+			arg->assign(args, arg, val);
+	}
+}
+
+
+/**
+  Parse args from stdin and assign to the specified args structure.
+  
+  @param optstr		Command line option string in getopt(3) format
+  @param args		Args structure to fill in.
+ */
+void
+args_get_getopt(int argc, char **argv, char *optstr, fence_xvm_args_t *args)
+{
+	int opt;
+	struct arg_info *arg;
+
+	while ((opt = getopt(argc, argv, optstr)) != EOF) {
+
+		arg = find_arg_by_char(opt);
+
+		if (!arg) {
+			args->flags |= F_ERR;
+			continue;
+		}
+
+		if (arg->assign)
+			arg->assign(args, arg, optarg);
+	}
+}
+
+
+void
+args_finalize(fence_xvm_args_t *args)
+{
+	char *addr = NULL;
+
+	if (!args->addr) {
+		switch(args->family) {
+		case 0:
+		case PF_INET:
+			addr = IPV4_MCAST_DEFAULT;
+			break;
+		case PF_INET6:
+			addr = IPV6_MCAST_DEFAULT;
+			break;
+		default:
+			args->flags |= F_ERR;
+		break;
+		}
+	}
+
+	if (!args->addr)
+		args->addr = addr;
+
+	if (!args->addr) {
+		printf("No multicast address available\n");
+		args->flags |= F_ERR;
+	}
+
+	if (!args->addr)
+		return;
+	if (args->family)
+		return;
+
+	/* Set family */
+	if (strchr(args->addr, ':'))
+		args->family = PF_INET6;
+	if (strchr(args->addr, '.'))
+		args->family = PF_INET;
+	if (!args->family) {
+		printf("Could not determine address family\n");
+		args->flags |= F_ERR;
+	}
+}
/cvs/cluster/cluster/fence/agents/xvm/options.h,v  -->  standard output
revision 1.2.2.1
--- cluster/fence/agents/xvm/options.h
+++ -	2006-12-01 15:49:40.217515000 +0000
@@ -0,0 +1,70 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#ifndef _XVM_OPTIONS_H
+#define _XVM_OPTIONS_H
+
+typedef enum {
+	F_FOREGROUND	= 0x1,
+	F_NOCCS		= 0x2,
+	F_ERR		= 0x4,
+	F_HELP		= 0x8,
+	F_USE_UUID	= 0x10,
+	F_VERSION	= 0x20,
+	F_CCSERR	= 0x40,
+	F_CCSFAIL	= 0x80
+} arg_flags_t;
+
+
+typedef struct {
+	char *addr;
+	char *domain;
+	char *key_file;
+	fence_cmd_t op;
+	fence_hash_t hash;
+	fence_auth_type_t auth;
+	int port;
+	int family;
+	int timeout;
+	int retr_time;
+	arg_flags_t flags;
+	int debug;
+} fence_xvm_args_t;
+
+/* Private structure for commandline / stdin fencing args */
+struct arg_info {
+	char opt;
+	char *opt_desc;
+	char *stdin_opt;
+	char *desc;
+	void (*assign)(fence_xvm_args_t *, struct arg_info *, char *);
+};
+
+
+/* Get options */
+void args_init(fence_xvm_args_t *args);
+void args_finalize(fence_xvm_args_t *args);
+
+void args_get_getopt(int argc, char **argv, char *optstr,
+		     fence_xvm_args_t *args);
+void args_get_stdin(char *optstr, fence_xvm_args_t *args);
+void args_get_ccs(char *optstr, fence_xvm_args_t *args);
+void args_usage(char *progname, char *optstr, int print_stdin);
+void args_print(fence_xvm_args_t *args);
+
+#endif
/cvs/cluster/cluster/fence/agents/xvm/simple_auth.c,v  -->  standard output
revision 1.3.2.1
--- cluster/fence/agents/xvm/simple_auth.c
+++ -	2006-12-01 15:49:40.330092000 +0000
@@ -0,0 +1,410 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sechash.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* Local includes */
+#include "xvm.h"
+#include "simple_auth.h"
+
+
+void
+print_hash(unsigned char *hash, size_t hashlen)
+{
+	int x; 
+
+	for (x = 0; x < hashlen; x++)
+		printf("%02x", (hash[x]&0xff));
+}
+
+
+static void
+sha_sign(fence_req_t *req, void *key, size_t key_len)
+{
+	unsigned char hash[SHA512_LENGTH];
+	HASHContext *h;
+	HASH_HashType ht;
+	unsigned int rlen;
+	int devrand;
+
+	switch(req->hashtype) {
+		case HASH_SHA1:
+			ht = HASH_AlgSHA1;
+			break;
+		case HASH_SHA256:
+			ht = HASH_AlgSHA256;
+			break;
+		case HASH_SHA512:
+			ht = HASH_AlgSHA512;
+			break;
+		default:
+			return;
+	}
+
+	dprintf(4, "Opening /dev/urandom\n");
+	devrand = open("/dev/urandom", O_RDONLY);
+	if (devrand >= 0) {
+		if (read(devrand, req->random, sizeof(req->random)) < 0) {
+			perror("read /dev/urandom");
+		}
+		close(devrand);
+	}
+
+	memset(hash, 0, sizeof(hash));
+	h = HASH_Create(ht);
+	if (!h)
+		return;
+
+	HASH_Begin(h);
+	HASH_Update(h, key, key_len);
+	HASH_Update(h, (void *)req, sizeof(req));
+	HASH_End(h, hash, &rlen, sizeof(hash));
+	HASH_Destroy(h);
+
+	memcpy(req->hash, hash, sizeof(req->hash));
+}
+
+
+static int
+sha_verify(fence_req_t *req, void *key, size_t key_len)
+{
+	unsigned char hash[SHA512_LENGTH];
+	unsigned char pkt_hash[SHA512_LENGTH];
+	HASHContext *h = NULL;
+	HASH_HashType ht;
+	unsigned int rlen;
+	int ret;
+
+	switch(req->hashtype) {
+		case HASH_SHA1:
+			ht = HASH_AlgSHA1;
+			break;
+		case HASH_SHA256:
+			ht = HASH_AlgSHA256;
+			break;
+		case HASH_SHA512:
+			ht = HASH_AlgSHA512;
+			break;
+		default:
+			dprintf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__);
+			return 0;
+	}
+
+	memset(hash, 0, sizeof(hash));
+	h = HASH_Create(ht);
+	if (!h)
+		return 0;
+
+	memcpy(pkt_hash, req->hash, sizeof(pkt_hash));
+	memset(req->hash, 0, sizeof(req->hash));
+
+	HASH_Begin(h);
+	HASH_Update(h, key, key_len);
+	HASH_Update(h, (void *)req, sizeof(req));
+	HASH_End(h, hash, &rlen, sizeof(hash));
+	HASH_Destroy(h);
+
+	memcpy(req->hash, pkt_hash, sizeof(req->hash));
+
+	ret = !memcmp(hash, pkt_hash, sizeof(hash));
+	if (!ret) {
+		printf("Hash mismatch:\nPKT = ");
+		print_hash(pkt_hash, sizeof(pkt_hash));
+		printf("\nEXP = ");
+		print_hash(hash, sizeof(hash));
+		printf("\n");
+	}
+
+	return ret;
+}
+
+
+int
+sign_request(fence_req_t *req, void *key, size_t key_len)
+{
+	memset(req->hash, 0, sizeof(req->hash));
+	switch(req->hashtype) {
+	case HASH_NONE:
+		dprintf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__);
+		return 0;
+	case HASH_SHA1:
+	case HASH_SHA256:
+	case HASH_SHA512:
+		sha_sign(req, key, key_len);
+		return 0;
+	default:
+		break;
+	}
+	return -1;
+}
+
+
+int
+verify_request(fence_req_t *req, fence_hash_t min,
+	       void *key, size_t key_len)
+{
+	if (req->hashtype < min) {
+		printf("Hash type not strong enough (%d < %d)\n",
+		       req->hashtype, min);
+		return 0;
+	}
+	switch(req->hashtype) {
+	case HASH_NONE:
+		return 1;
+	case HASH_SHA1:
+	case HASH_SHA256:
+	case HASH_SHA512:
+		return sha_verify(req, key, key_len);
+	default:
+		break;
+	}
+	return 0;
+}
+
+
+int
+sha_challenge(int fd, fence_auth_type_t auth, void *key,
+	      size_t key_len, int timeout)
+{
+	fd_set rfds;
+	struct timeval tv;
+	unsigned char hash[MAX_HASH_LENGTH];
+	unsigned char challenge[MAX_HASH_LENGTH];
+	unsigned char response[MAX_HASH_LENGTH];
+	int devrand;
+	int ret;
+	HASHContext *h;
+	HASH_HashType ht;
+	unsigned int rlen;
+
+	devrand = open("/dev/urandom", O_RDONLY);
+	if (read(devrand, challenge, sizeof(challenge)) < 0) {
+		perror("read /dev/urandom");
+		return 0;
+	}
+	close(devrand);
+
+	if (write(fd, challenge, sizeof(challenge)) < 0) {
+		perror("write");
+		return 0;
+	}
+
+	switch(auth) {
+		case HASH_SHA1:
+			ht = HASH_AlgSHA1;
+			break;
+		case HASH_SHA256:
+			ht = HASH_AlgSHA256;
+			break;
+		case HASH_SHA512:
+			ht = HASH_AlgSHA512;
+			break;
+		default:
+			return 0;
+	}
+
+	memset(hash, 0, sizeof(hash));
+	h = HASH_Create(ht);
+	if (!h)
+		return 0;
+
+	HASH_Begin(h);
+	HASH_Update(h, key, key_len);
+	HASH_Update(h, challenge, sizeof(challenge));
+	HASH_End(h, hash, &rlen, sizeof(hash));
+	HASH_Destroy(h);
+
+	memset(response, 0, sizeof(response));
+
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+	if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
+		perror("select");
+		return 0;
+	}
+
+	if (read(fd, response, sizeof(response)) < sizeof(response)) {
+		perror("read");
+		return 0;
+	}
+
+	ret = !memcmp(response, hash, sizeof(response));
+	if (!ret) {
+		printf("Hash mismatch:\nC = ");
+		print_hash(challenge, sizeof(challenge));
+		printf("\nH = ");
+		print_hash(hash, sizeof(hash));
+		printf("\nR = ");
+		print_hash(response, sizeof(response));
+		printf("\n");
+	}
+
+	return ret;
+}
+
+
+int
+sha_response(int fd, fence_auth_type_t auth, void *key,
+	     size_t key_len, int timeout)
+{
+	fd_set rfds;
+	struct timeval tv;
+	unsigned char challenge[MAX_HASH_LENGTH];
+	unsigned char hash[MAX_HASH_LENGTH];
+	HASHContext *h;
+	HASH_HashType ht;
+	unsigned int rlen;
+
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+	if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
+		perror("select");
+		return 0;
+	}
+
+	if (read(fd, challenge, sizeof(challenge)) < 0) {
+		perror("read");
+		return 0;
+	}
+
+	switch(auth) {
+		case AUTH_SHA1:
+			ht = HASH_AlgSHA1;
+			break;
+		case AUTH_SHA256:
+			ht = HASH_AlgSHA256;
+			break;
+		case AUTH_SHA512:
+			ht = HASH_AlgSHA512;
+			break;
+		default:
+			dprintf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
+			return 0;
+	}
+
+	memset(hash, 0, sizeof(hash));
+	h = HASH_Create(ht); /* */
+	if (!h)
+		return 0;
+
+	HASH_Begin(h);
+	HASH_Update(h, key, key_len);
+	HASH_Update(h, challenge, sizeof(challenge));
+	HASH_End(h, hash, &rlen, sizeof(hash));
+	HASH_Destroy(h);
+
+	if (write(fd, hash, sizeof(hash)) < sizeof(hash)) {
+		perror("read");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+int
+tcp_challenge(int fd, fence_auth_type_t auth, void *key, size_t key_len,
+	      int timeout)
+{
+	switch(auth) {
+	case AUTH_NONE:
+		dprintf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
+		return 1;
+	case AUTH_SHA1:
+	case AUTH_SHA256:
+	case AUTH_SHA512:
+		return sha_challenge(fd, auth, key, key_len, timeout);
+	default:
+		break;
+	}
+	return -1;
+}
+
+
+int
+tcp_response(int fd, fence_auth_type_t auth, void *key, size_t key_len,
+	     int timeout)
+{
+	switch(auth) {
+	case AUTH_NONE:
+		dprintf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
+		return 1;
+	case AUTH_SHA1:
+	case AUTH_SHA256:
+	case AUTH_SHA512:
+		return sha_response(fd, auth, key, key_len, timeout);
+	default:
+		break;
+	}
+	return -1;
+}
+
+
+int
+read_key_file(char *file, char *key, size_t max_len)
+{
+	int fd;
+	int nread, remain = max_len;
+	char *p;
+
+	dprintf(3, "Reading in key file %s into %p (%d len)",
+		file, key, (int)max_len);
+	fd = open(file, O_RDONLY);
+	if (fd < 0) {
+		return -1;
+	}
+
+	memset(key, 0, max_len);
+	p = key;
+	remain = max_len;
+
+	while (remain) {
+		nread = read(fd, p, remain);
+		if (nread < 0) {
+			dprintf(2, "Error from read: %s\n", strerror(errno));
+			close(fd);
+			return -1;
+		}
+
+		if (nread == 0) {
+			dprintf(3, "Stopped reading @ %d bytes",
+				(int)max_len-remain);
+			break;
+		}
+		
+		p += nread;
+		remain -= nread;
+	}
+
+	dprintf(3, "Actual key length = %d bytes", (int)max_len-remain);
+	close(fd);	
+	
+	return 0;
+}
/cvs/cluster/cluster/fence/agents/xvm/simple_auth.h,v  -->  standard output
revision 1.1.6.1
--- cluster/fence/agents/xvm/simple_auth.h
+++ -	2006-12-01 15:49:40.710929000 +0000
@@ -0,0 +1,35 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#ifndef _XVM_SIMPLE_AUTH_H
+#define _XVM_SIMPLE_AUTH_H
+
+#include <sys/types.h>
+
+/* 2-way challenge/response simple auth */
+#define DEFAULT_KEY_FILE "/etc/cluster/fence_xvm.key"
+
+int read_key_file(char *, char *, size_t);
+int tcp_challenge(int, fence_auth_type_t, void *, size_t, int);
+int tcp_response(int, fence_auth_type_t, void *, size_t, int);
+int sign_request(fence_req_t *, void *, size_t);
+int verify_request(fence_req_t *, fence_hash_t, void *, size_t);
+
+/* SSL certificate-based authentication TBD */
+
+#endif
/cvs/cluster/cluster/fence/agents/xvm/tcp.c,v  -->  standard output
revision 1.2.2.1
--- cluster/fence/agents/xvm/tcp.c
+++ -	2006-12-01 15:49:41.038003000 +0000
@@ -0,0 +1,298 @@
+/*
+  Copyright Red Hat, Inc. 2002-2004, 2006
+  Copyright Mission Critical Linux, 2000
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge,
+  MA 02139, USA.
+*/
+/** @file
+ *
+ * @author Lon H. Hohberger <lhh at redhat.com>
+ * @author Jeff Moyer <jmoyer at redhat.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+
+static int connect_nb(int fd, struct sockaddr *dest, socklen_t len, int timeout);
+
+/**
+  Set close-on-exec bit option for a socket.
+
+   @param fd		Socket to set CLOEXEC flag
+   @return		0 on success, -1 on failure
+   @see			fcntl
+ */
+static int 
+set_cloexec(int fd)
+{
+	int flags = fcntl(fd, F_GETFD, 0);
+	flags |= FD_CLOEXEC;
+	return fcntl(fd, F_SETFD, flags);
+}
+
+
+/**
+  Bind to a port on the local IPv6 stack
+
+  @param port		Port to bind to
+  @param backlog	same as backlog for listen(2)
+  @return		0 on success, -1 on failure
+  @see			ipv4_bind
+ */
+int
+ipv6_listen(uint16_t port, int backlog)
+{
+	struct sockaddr_in6 _sin6;
+	int fd, ret;
+
+	dprintf(4, "%s: Setting up ipv6 listen socket\n", __FUNCTION__);
+	fd = socket(PF_INET6, SOCK_STREAM, 0);
+	if (fd < 0)
+		return -1;
+
+	memset(&_sin6, 0, sizeof(_sin6));
+	_sin6.sin6_family = PF_INET6;
+	_sin6.sin6_port = htons(port);
+	_sin6.sin6_flowinfo = 0;
+	_sin6.sin6_addr = in6addr_any;
+
+	ret = 1;
+	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&ret, sizeof (ret));
+
+	ret = set_cloexec(fd);
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+
+	ret = bind(fd, (struct sockaddr *)&_sin6, sizeof(_sin6));
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+
+	if (listen(fd, backlog) < 0){
+		close(fd);
+		return -1;
+	}
+
+	dprintf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd);
+	return fd;
+}
+
+
+/**
+  Bind to a port on the local IPv4 stack
+
+  @param port		Port to bind to
+  @param backlog	same as backlog for listen(2)
+  @return		0 on success, -1 on failure
+  @see			ipv6_bind
+ */
+int
+ipv4_listen(uint16_t port, int backlog)
+{
+	struct sockaddr_in _sin;
+	int fd, ret;
+
+	dprintf(4, "%s: Setting up ipv4 listen socket\n", __FUNCTION__);
+	fd = socket(PF_INET, SOCK_STREAM, 0);
+	if (fd < 0)
+		return -1;
+
+	_sin.sin_family = PF_INET;
+	_sin.sin_port = htons(port);
+	_sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+	ret = 1;
+	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&ret, sizeof (ret));
+	
+	ret = set_cloexec(fd);
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+
+	ret = bind(fd, (struct sockaddr *)&_sin, sizeof(_sin));
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+
+	if (listen(fd, backlog) < 0){
+		close(fd);
+		return -1;
+	}
+
+	dprintf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd);
+	return fd;
+}
+
+
+
+/**
+  Connect via ipv6 socket to a given IP address and port.
+
+  @param in6_addr	IPv6 address to connect to
+  @param port		Port to connect to
+  @param timeout	Timeout, in seconds, to wait for a completed
+  			connection
+  @return 		0 on success, -1 on failure
+  @see			connect_nb, ipv4_connect
+ */
+int
+ipv6_connect(struct in6_addr *in6_addr, uint16_t port, int timeout)
+{
+	struct sockaddr_in6 _sin6;
+	int fd, ret;
+
+	dprintf(4, "%s: Connecting to client\n", __FUNCTION__);
+	fd = socket(PF_INET6, SOCK_STREAM, 0);
+	if (fd < 0)
+		return -1;
+
+	memset(&_sin6, 0, sizeof(_sin6));
+	_sin6.sin6_family = PF_INET6;
+	_sin6.sin6_port = htons(port);
+	_sin6.sin6_flowinfo = 0;
+	memcpy(&_sin6.sin6_addr, in6_addr, sizeof(_sin6.sin6_addr));
+
+	ret = connect_nb(fd, (struct sockaddr *)&_sin6, sizeof(_sin6), timeout);
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+	dprintf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd);
+	return fd;
+}
+
+
+/**
+  Connect via ipv4 socket to a given IP address and port.
+
+  @param in_addr	IPv4 address to connect to
+  @param port		Port to connect to
+  @param timeout	Timeout, in seconds, to wait for a completed
+  			connection
+  @return 		0 on success, -1 on failure
+  @see			connect_nb, ipv6_connect
+ */
+int
+ipv4_connect(struct in_addr *in_addr, uint16_t port, int timeout)
+{
+	struct sockaddr_in _sin;
+	int fd, ret;
+
+	dprintf(4, "%s: Connecting to client\n", __FUNCTION__);
+	fd = socket(PF_INET, SOCK_STREAM, 0);
+	if (fd < 0)
+		return -1;
+
+	_sin.sin_family = PF_INET;
+	_sin.sin_port = htons(port);
+	memcpy(&_sin.sin_addr, in_addr, sizeof(_sin.sin_addr));
+
+	ret = connect_nb(fd, (struct sockaddr *)&_sin, sizeof(_sin), timeout);
+	if (ret < 0) {
+		close(fd);
+		return -1;
+	}
+
+	dprintf(4, "%s: Success; fd = %d\n", __FUNCTION__, fd);
+	return fd;
+}
+
+
+/**
+  Connect in a non-blocking fashion to the designated address.
+
+  @param fd		File descriptor to connect
+  @param dest		sockaddr (ipv4 or ipv6) to connect to.
+  @param len		Length of dest
+  @param timeout	Timeout, in seconds, to wait for a completed
+  			connection.
+  @return		0 on success, -1 on failure.
+ */
+static int
+connect_nb(int fd, struct sockaddr *dest, socklen_t len, int timeout)
+{
+	int ret, flags = 1, err;
+	unsigned l;
+	fd_set rfds, wfds;
+	struct timeval tv;
+
+	/*
+	 * Use TCP Keepalive
+	 */
+	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags,
+		       sizeof(flags))<0)
+		return -1;
+			
+	/*
+	   Set up non-blocking connect
+	 */
+	flags = fcntl(fd, F_GETFL, 0);
+	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+	ret = connect(fd, dest, len);
+
+	if ((ret < 0) && (errno != EINPROGRESS))
+		return -1;
+
+	if (ret != 0) {
+		FD_ZERO(&rfds);
+		FD_SET(fd, &rfds);
+		FD_ZERO(&wfds);
+		FD_SET(fd, &wfds);
+
+		tv.tv_sec = timeout;
+		tv.tv_usec = 0;
+		
+		if (select(fd + 1, &rfds, &wfds, NULL, &tv) == 0) {
+			errno = ETIMEDOUT;
+			return -1;
+		}
+		/* XXX check for -1 from select */
+
+		if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds)) {
+			l = sizeof(err);
+			if (getsockopt(fd, SOL_SOCKET, SO_ERROR,
+				       (void *)&err, &l) < 0) {
+				close(fd);
+				return -1;
+			}
+
+			if (err != 0) {
+				close(fd);
+				errno = err;
+				return -1;
+			}
+
+			fcntl(fd, F_SETFL, flags);
+			return 0;
+		}
+	}
+
+	errno = EIO;
+	return -1;
+}
/cvs/cluster/cluster/fence/agents/xvm/tcp.h,v  -->  standard output
revision 1.1.6.1
--- cluster/fence/agents/xvm/tcp.h
+++ -	2006-12-01 15:49:41.151694000 +0000
@@ -0,0 +1,27 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#ifndef _XVM_TCP_H
+#define _XVM_TCP_H
+
+int ipv4_connect(struct in_addr *in_addr, uint16_t port, int timeout);
+int ipv6_connect(struct in6_addr *in6_addr, uint16_t port, int timeout);
+int ipv4_listen(uint16_t port, int backlog);
+int ipv6_listen(uint16_t port, int backlog);
+
+#endif
/cvs/cluster/cluster/fence/agents/xvm/xvm.h,v  -->  standard output
revision 1.2.2.1
--- cluster/fence/agents/xvm/xvm.h
+++ -	2006-12-01 15:49:41.429287000 +0000
@@ -0,0 +1,86 @@
+/*
+  Copyright Red Hat, Inc. 2006
+
+  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, 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; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc.,  675 Mass Ave, Cambridge, 
+  MA 02139, USA.
+*/
+#ifndef _XVM_H
+#define _XVM_H
+
+#include <stdint.h>
+#include <sechash.h>
+#include <netinet/in.h>
+
+#define XVM_VERSION "0.9.3"
+
+#define MAX_DOMAINNAME_LENGTH 64 /* XXX MAXHOSTNAMELEN */
+#define MAX_ADDR_LEN		sizeof(struct sockaddr_in6)
+#define DOMAIN0NAME "Domain-0"
+#define DOMAIN0UUID "00000000-0000-0000-0000-000000000000"
+
+typedef enum {
+	HASH_NONE = 0x0,	/* No packet signing */
+	HASH_SHA1 = 0x1,	/* SHA1 signing */
+     	HASH_SHA256 = 0x2,      /* SHA256 signing */
+     	HASH_SHA512 = 0x3       /* SHA512 signing */
+} fence_hash_t;
+
+#define DEFAULT_HASH HASH_SHA256
+
+typedef enum {
+	AUTH_NONE = 0x0,	/* Plain TCP */
+	AUTH_SHA1 = 0x1,	/* Challenge-response (SHA1) */
+  	AUTH_SHA256 = 0x2,      /* Challenge-response (SHA256) */
+	AUTH_SHA512 = 0x3,      /* Challenge-response (SHA512) */
+     /* AUTH_SSL_X509 = 0x10        SSL X509 certificates */
+} fence_auth_type_t;
+
+#define DEFAULT_AUTH AUTH_SHA256
+
+typedef enum {
+	FENCE_NULL   = 0x0,	
+	FENCE_OFF    = 0x1,	/* Turn the VM off */
+	FENCE_REBOOT = 0x2	/* Hit the reset button */
+     /* FENCE_ON = 0x3            Turn the VM on */
+} fence_cmd_t;
+
+#define MAX_HASH_LENGTH SHA512_LENGTH
+
+typedef struct __attribute__ ((packed)) _fence_req {
+	uint8_t  request;		/* Fence request */
+	uint8_t  hashtype;		/* Hash type used */
+	uint8_t  addrlen;		/* Length of address */
+	uint8_t  flags;			/* Special flags */
+#define RF_UUID 0x1			   /* Flag specifying UUID */
+	uint8_t  domain[MAX_DOMAINNAME_LENGTH]; /* Domain to fence*/
+	uint8_t  address[MAX_ADDR_LEN]; /* We're this IP */
+	uint16_t port;			/* Port we bound to */
+	uint8_t  random[10];		/* Random Data */
+	uint32_t family;		/* Address family */
+	uint8_t  hash[MAX_HASH_LENGTH];	/* Binary hash */
+} fence_req_t;
+
+
+inline void dset(int);
+inline int dget(void);
+
+#define dprintf(level, fmt, args...) \
+do { \
+	if (dget()>=level) \
+		printf(fmt, ##args); \
+} while(0)
+	
+
+#endif




More information about the Cluster-devel mailing list