All of lore.kernel.org
 help / color / mirror / Atom feed
* [Cluster-devel] cluster/fence/agents/xvm Makefile README TODO  ...
@ 2006-12-01 15:49 lhh
  0 siblings, 0 replies; only message in thread
From: lhh @ 2006-12-01 15:49 UTC (permalink / raw)
  To: cluster-devel.redhat.com

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@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@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@redhat.com>
+ * @author Jeff Moyer <jmoyer@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



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-12-01 15:49 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-01 15:49 [Cluster-devel] cluster/fence/agents/xvm Makefile README TODO lhh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.