#ifndef lint
static char copyright[] =
-"$Id: failover.c,v 1.4 1999/11/20 18:36:31 mellon Exp $ Copyright (c) 1999 The Internet Software Consortium. All rights reserved.\n";
+"$Id: failover.c,v 1.5 1999/11/23 22:25:07 mellon Exp $ Copyright (c) 1999 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
+#include "version.h"
#include <omapip/omapip_p.h>
#if defined (FAILOVER_PROTOCOL)
"dhcp_failover_link_get_value");
return omapi_make_string_value
(value, name,
- dhcp_failover_link_state_names [link -> state],
+ dhcp_flink_state_names [link -> state],
"dhcp_failover_link_get_value");
}
status = omapi_connection_put_string (c, "invalid link state");
else
status = (omapi_connection_put_string
- (c, dhcp_failover_link_state_names [link -> state]));
+ (c, dhcp_flink_state_names [link -> state]));
if (status != ISC_R_SUCCESS)
return status;
specified connection. */
isc_result_t dhcp_failover_state_stuff (omapi_object_t *c,
- omapi_object_t *id,
- omapi_object_t *p)
+ omapi_object_t *id,
+ omapi_object_t *p)
{
int i;
return ISC_R_SUCCESS;
}
+isc_result_t dhcp_failover_state_lookup (omapi_object_t **sp,
+ omapi_object_t *id,
+ omapi_object_t *ref)
+{
+ omapi_value_t *tv = (omapi_value_t *)0;
+ isc_result_t status;
+ dhcp_failover_state_t *s;
+
+ /* First see if we were sent a handle. */
+ status = omapi_get_value_str (ref, id, "handle", &tv);
+ if (status == ISC_R_SUCCESS) {
+ status = omapi_handle_td_lookup (sp, tv -> value);
+
+ omapi_value_dereference (&tv, "dhcp_failover_state_lookup");
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ /* Don't return the object if the type is wrong. */
+ if ((*sp) -> type != dhcp_type_failover_state) {
+ omapi_object_dereference
+ (sp, "dhcp_failover_state_lookup");
+ return ISC_R_INVALIDARG;
+ }
+ }
+
+ /* Look the lease up by peer name. */
+ status = omapi_get_value_str (ref, id, "peer_name", &tv);
+ if (status == ISC_R_SUCCESS) {
+ for (s = failover_states; s; s = s -> next) {
+ unsigned l = strlen (s -> remote_peer);
+ if (l == tv -> value -> u.buffer.len ||
+ !memcmp (s -> remote_peer,
+ tv -> value -> u.buffer.value, l))
+ break;
+ }
+ omapi_value_dereference (&tv, "dhcp_failover_state_lookup");
+
+ /* If we already have a lease, and it's not the same one,
+ then the query was invalid. */
+ if (*sp && *sp != (omapi_object_t *)s) {
+ omapi_object_dereference
+ (sp, "dhcp_failover_state_lookup");
+ return ISC_R_KEYCONFLICT;
+ } else if (!s) {
+ if (*sp)
+ omapi_object_dereference
+ (sp, "dhcp_failover_state_lookup");
+ return ISC_R_NOTFOUND;
+ } else if (!*sp)
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (sp, (omapi_object_t *)s,
+ "dhcp_failover_state_lookup");
+ }
+
+ /* If we get to here without finding a lease, no valid key was
+ specified. */
+ if (!*sp)
+ return ISC_R_NOKEYS;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_failover_state_create (omapi_object_t **sp,
+ omapi_object_t *id)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+
+isc_result_t dhcp_failover_state_remove (omapi_object_t *sp,
+ omapi_object_t *id)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+
+failover_option_t *dhcp_failover_make_option (unsigned code,
+ char *obuf, unsigned *obufix,
+ unsigned obufmax, ...)
+{
+ va_list va;
+ struct failover_option_info *info;
+ int i;
+ unsigned size, count;
+ unsigned val;
+ struct iaddr *ival;
+ u_int8_t *bval;
+ char *fmt;
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ char tbuf [256];
+#endif
+ /* Note that the failover_option structure is used differently on
+ input than on output - on input, count is an element count, and
+ on output it's the number of bytes total in the option, including
+ the option code and option length. */
+ failover_option_t option, *op;
+
+
+ /* Bogus option code? */
+ if (code < 1 || code > FTO_MAX || ft_options [code].type == FT_UNDEF) {
+ return &null_failover_option;
+ }
+ info = &ft_options [code];
+
+ va_start (va, obufmax);
+
+ /* Get the number of elements and the size of the buffer we need
+ to allocate. */
+ if (info -> type == FT_DDNS || info -> type == FT_DDNS1) {
+ count = info -> type == FT_DDNS ? 1 : 2;
+ size = va_arg (va, int) + count;
+ } else {
+ /* Find out how many items in this list. */
+ if (info -> num_present)
+ count = info -> num_present;
+ else
+ count = va_arg (va, int);
+
+ /* Figure out size. */
+ switch (info -> type) {
+ case FT_UINT8:
+ case FT_BYTES:
+ case FT_DIGEST:
+ size = count;
+ break;
+
+ case FT_TEXT_OR_BYTES:
+ case FT_TEXT:
+ fmt = va_arg (va, char *);
+#if defined (HAVE_SNPRINTF)
+ /* Presumably if we have snprintf, we also have
+ vsnprintf. */
+ vsnprintf (tbuf, sizeof tbuf, fmt, va);
+#else
+ vsprintf (tbuf, fmt, va);
+#endif
+ size = strlen (tbuf);
+ count = size;
+ break;
+
+ case FT_IPADDR:
+ case FT_UINT32:
+ size = count * 4;
+ break;
+
+ case FT_UINT16:
+ size = count * 2;
+ break;
+
+ default:
+ /* shouldn't get here. */
+ log_fatal ("bogus type in failover_make_option: %d",
+ info -> type);
+ break;
+ }
+ }
+
+ size += 4;
+
+ /* Allocate a buffer for the option. */
+ option.count = size;
+ option.data = dmalloc (option.count, "dhcp_failover_make_option");
+ if (!option.data)
+ return &null_failover_option;
+
+ /* Put in the option code and option length. */
+ putUShort (option.data, code);
+ putUShort (&option.data [4], size - 4);
+
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ sprintf (tbuf, " (%s<%d>", info -> name, option.count);
+ failover_print (obuf, obufix, obufmax, tbuf);
+#endif
+
+ /* Now put in the data. */
+ switch (info -> type) {
+ case FT_UINT8:
+ for (i = 0; i < count; i++) {
+ val = va_arg (va, unsigned);
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ sprintf (tbuf, " %d", val);
+ failover_print (obuf, obufix, obufmax, tbuf);
+#endif
+ option.data [i + 4] = val;
+ }
+ break;
+
+ case FT_IPADDR:
+ for (i = 0; i < count; i++) {
+ ival = va_arg (va, struct iaddr *);
+ if (ival -> len != 4) {
+ dfree (option.data,
+ "dhcp_failover_make_option");
+ log_error ("IP addrlen=%d, should be 4.",
+ ival -> len);
+ return &null_failover_option;
+ }
+
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ sprintf (tbuf, " %s", piaddr (*ival));
+ failover_print (obuf, obufix, obufmax, tbuf);
+#endif
+ memcpy (&option.data [4 + i * 4], ival -> iabuf, 4);
+ }
+ break;
+
+ case FT_UINT32:
+ for (i = 0; i < count; i++) {
+ val = va_arg (va, unsigned);
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ sprintf (tbuf, " %d", val);
+ failover_print (obuf, obufix, obufmax, tbuf);
+#endif
+ putULong (&option.data [4 + i * 4], val);
+ }
+ break;
+
+ case FT_BYTES:
+ case FT_DIGEST:
+ bval = va_arg (va, u_int8_t *);
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ for (i = 0; i < count; i++) {
+ sprintf (tbuf, " %d", bval [i]);
+ failover_print (obuf, obufix, obufmax, tbuf);
+ }
+#endif
+ memcpy (&option.data [4], bval, count);
+ break;
+
+ /* On output, TEXT_OR_BYTES is _always_ text, and always NUL
+ terminated. Note that the caller should be careful not to
+ provide a format and data that amount to more than 256 bytes
+ of data, since it will be truncated on platforms that
+ support snprintf, and will mung the stack on those platforms
+ that do not support snprintf. Also, callers should not pass
+ data acquired from the network without specifically checking
+ it to make sure it won't bash the stack. */
+ case FT_TEXT_OR_BYTES:
+ case FT_TEXT:
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ failover_print (obuf, obufix, obufmax, " \"");
+ failover_print (obuf, obufix, obufmax, tbuf);
+ failover_print (obuf, obufix, obufmax, "\"");
+#endif
+ memcpy (&option.data [4], tbuf, count);
+ break;
+
+ case FT_DDNS:
+ case FT_DDNS1:
+ option.data [4] = va_arg (va, unsigned);
+ if (count == 2)
+ option.data [5] = va_arg (va, unsigned);
+ bval = va_arg (va, u_int8_t *);
+ memcpy (&option.data [4 + count], bval, size - count - 4);
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ for (i = 4; i < size; i++) {
+ sprintf (tbuf, " %d", option.data [i]);
+ failover_print (obuf, obufix, obufmax, tbuf);
+ }
+#endif
+ break;
+
+ case FT_UINT16:
+ for (i = 0; i < count; i++) {
+ val = va_arg (va, u_int32_t);
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ sprintf (tbuf, " %d", val);
+ failover_print (obuf, obufix, obufmax, tbuf);
+#endif
+ putUShort (&option.data [4 + i * 2], val);
+ }
+ break;
+
+ case FT_UNDEF:
+ default:
+ }
+
+ failover_print (obuf, obufix, obufmax, ")");
+
+ /* Now allocate a place to store what we just set up. */
+ op = dmalloc (sizeof (failover_option_t),
+ "dhcp_failover_make_option");
+ if (!op) {
+ dfree (option.data, "dhcp_failover_make_option");
+ return &null_failover_option;
+ }
+
+ *op = option;
+ return op;
+}
+
+/* Send a failover message header. */
+
+isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *link,
+ omapi_object_t *connection,
+ int msg_type, ...)
+{
+ unsigned count = 0;
+ unsigned size = 0;
+ int bad_option = 0;
+ int opix = 0;
+ va_list list;
+ failover_option_t *option;
+ unsigned char *opbuf;
+ isc_result_t status = ISC_R_SUCCESS;
+ unsigned char cbuf;
+
+ /* Run through the argument list once to compute the length of
+ the option portion of the message. */
+ va_start (list, msg_type);
+ while ((option = va_arg (list, failover_option_t *))) {
+ size += option -> count;
+ if (option == &null_failover_option)
+ bad_option = 1;
+ }
+ va_end (list);
+
+ /* Allocate an option buffer, unless we got an error. */
+ if (!bad_option) {
+ opbuf = dmalloc (size, "dhcp_failover_put_message");
+ if (!opbuf)
+ status = ISC_R_NOMEMORY;
+ }
+
+ va_start (list, msg_type);
+ while ((option = va_arg (list, failover_option_t *))) {
+ if (!bad_option && opbuf)
+ memcpy (&opbuf [opix],
+ option -> data, option -> count);
+ opix += option -> count;
+ dfree (option -> data, "dhcp_failover_put_message");
+ dfree (option, "dhcp_failover_put_message");
+ }
+
+ if (bad_option || !opbuf)
+ return status;
+
+ /* Now send the message header. */
+
+ /* Message length. */
+ status = omapi_connection_put_uint16 (connection, size + 12);
+ if (status != ISC_R_SUCCESS)
+ goto err;
+
+ /* Message type. */
+ cbuf = msg_type;
+ status = omapi_connection_copyin (connection, &cbuf, 1);
+ if (status != ISC_R_SUCCESS)
+ goto err;
+
+ /* Payload offset. */
+ cbuf = 12;
+ status = omapi_connection_copyin (connection, &cbuf, 1);
+ if (status != ISC_R_SUCCESS)
+ goto err;
+
+ /* Current time. */
+ status = omapi_connection_put_uint32 (connection, (u_int32_t)cur_time);
+ if (status != ISC_R_SUCCESS)
+ goto err;
+
+ /* Transaction ID. */
+ status = omapi_connection_put_uint32 (connection, link -> xid++);
+ if (status != ISC_R_SUCCESS)
+ goto err;
+
+
+ /* Payload. */
+ status = omapi_connection_copyin (connection, opbuf, size);
+ if (status != ISC_R_SUCCESS)
+ goto err;
+ dfree (opbuf, "dhcp_failover_put_message");
+ return status;
+
+ err:
+ dfree (opbuf, "dhcp_failover_put_message");
+ omapi_disconnect (connection, 1);
+ return status;
+}
+
+/* Send a connect message. */
+
+isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
+{
+ dhcp_failover_link_t *link;
+ dhcp_failover_state_t *state;
+ isc_result_t status;
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ char obuf [64];
+ unsigned obufix = 0;
+
+# define FMA obuf, &obufix, sizeof obuf
+ failover_print (FMA, "(connect");
+#else
+# define FMA (unsigned char *)0, (unsigned *)0, 0
+#endif
+
+
+ if (!l || l -> type != dhcp_type_failover_link)
+ return ISC_R_INVALIDARG;
+ link = (dhcp_failover_link_t *)l;
+ state = link -> state_object;
+ if (!l -> outer || l -> outer -> type != omapi_type_connection)
+ return ISC_R_INVALIDARG;
+
+ status = (dhcp_failover_put_message
+ (link, l -> outer,
+ FTM_CONNECT,
+ dhcp_failover_make_option (FTO_SERVER_ADDR, FMA,
+ &state -> server_addr),
+ dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
+ state -> max_flying_updates),
+ dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA,
+ state -> partner_timeout),
+ dhcp_failover_make_option (FTO_VENDOR_CLASS, FMA,
+ "isc-%s", DHCP_VERSION),
+ dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA,
+ DHCP_FAILOVER_VERSION),
+ dhcp_failover_make_option (FTO_TLS_REQUEST, FMA,
+ 0, 0),
+ dhcp_failover_make_option (FTO_MCLT, FMA,
+ state -> mclt),
+ dhcp_failover_make_option (FTO_HBA, FMA,
+ state -> hba),
+ (failover_option_t *)0));
+
+#if defined (DEBUG_FAILOVER_MESSAGES)
+ if (status != ISC_R_SUCCESS)
+ failover_print (FMA, " (failed)");
+ failover_print (FMA, ")");
+ if (obufix) {
+ log_debug ("%s", obuf);
+ }
+#endif
+ return status;
+}
+
+#if defined (DEBUG_FAILOVER_MESSAGES)
+/* Print hunks of failover messages, doing line breaks as appropriate.
+ Note that this assumes syslog is being used, rather than, e.g., the
+ Windows NT logging facility, where just dumping the whole message in
+ one hunk would be more appropriate. */
+
+void failover_print (char *obuf,
+ unsigned *obufix, unsigned obufmax, const char *s)
+{
+ int len = strlen (s);
+
+ if (len + *obufix + 1 >= obufmax) {
+ if (!*obufix) {
+ log_debug ("%s", s);
+ return;
+ }
+ log_debug ("%s", obuf);
+ *obufix = 0;
+ } else {
+ strcpy (&obuf [*obufix], s);
+ obufix += len;
+ }
+}
+#endif /* defined (DEBUG_FAILOVER_MESSAGES) */
#endif /* defined (FAILOVER_PROTOCOL) */