[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