📄 failover.c
字号:
status = do_a_failover_option (c, link); if (status != ISC_R_SUCCESS) goto dhcp_flink_fail; } /* If it's a connect message, try to associate it with a state object. */ /* XXX this should be authenticated! */ if (link -> imsg -> type == FTM_CONNECT) { const char *errmsg; int reason; /* See if we can find a failover_state object that matches this connection. This message should only be received by a secondary from a primary. */ for (s = failover_states; s; s = s -> next) { if (dhcp_failover_state_match (s, (u_int8_t *)&link -> imsg -> server_addr, sizeof link -> imsg -> server_addr)) state = s; } /* If we can't find a failover protocol state for this remote host, drop the connection */ if (!state) { errmsg = "unknown server"; reason = FTR_INVALID_PARTNER; badconnect: /* XXX Send a refusal message first? XXX Look in protocol spec for guidance. */ log_error ("Failover CONNECT from %u.%u.%u.%u: %s", ((u_int8_t *) (&link -> imsg -> server_addr)) [0], ((u_int8_t *) (&link -> imsg -> server_addr)) [1], ((u_int8_t *) (&link -> imsg -> server_addr)) [2], ((u_int8_t *) (&link -> imsg -> server_addr)) [3], errmsg); dhcp_failover_send_connectack ((omapi_object_t *)link, state, reason, errmsg); log_info ("failover: disconnect: %s", errmsg); omapi_disconnect (c, 0); link -> state = dhcp_flink_disconnected; return ISC_R_SUCCESS; } if ((cur_time > link -> imsg -> time && cur_time - link -> imsg -> time > 60) || (cur_time < link -> imsg -> time && link -> imsg -> time - cur_time > 60)) { errmsg = "time offset too large"; reason = FTR_TIMEMISMATCH; goto badconnect; } if (!(link -> imsg -> options_present & FTB_HBA) || link -> imsg -> hba.count != 32) { errmsg = "invalid HBA"; reason = FTR_HBA_CONFLICT; /* XXX */ goto badconnect; } if (state -> hba) dfree (state -> hba, MDL); state -> hba = dmalloc (32, MDL); if (!state -> hba) { errmsg = "no memory"; reason = FTR_MISC_REJECT; goto badconnect; } memcpy (state -> hba, link -> imsg -> hba.data, 32); if (!link -> state_object) dhcp_failover_state_reference (&link -> state_object, state, MDL); if (!link -> peer_address) option_cache_reference (&link -> peer_address, state -> partner.address, MDL); } /* If we don't have a state object at this point, it's some kind of bogus situation, so just drop the connection. */ if (!link -> state_object) { log_info ("failover: connect: no matching state."); omapi_disconnect (c, 1); link -> state = dhcp_flink_disconnected; return ISC_R_INVALIDARG; } /* Once we have the entire message, and we've validated it as best we can here, pass it to the parent. */ omapi_signal ((omapi_object_t *)link -> state_object, "message", link); link -> state = dhcp_flink_message_length_wait; failover_message_dereference (&link -> imsg, MDL); /* XXX This is dangerous because we could get into a tight XXX loop reading input without servicing any other stuff. XXX There needs to be a way to relinquish control but XXX get it back immediately if there's no other work to XXX do. */ if ((omapi_connection_require (c, 2)) == ISC_R_SUCCESS) goto next_message; break; default: /* XXX should never get here. Assertion? */ break; } return ISC_R_SUCCESS;}static isc_result_t do_a_failover_option (c, link) omapi_object_t *c; dhcp_failover_link_t *link;{ u_int16_t option_code; u_int16_t option_len; unsigned char *op; unsigned op_size; unsigned op_count; int i; isc_result_t status; if (link -> imsg_count + 2 > link -> imsg_len) { log_error ("FAILOVER: message overflow at option code."); return ISC_R_PROTOCOLERROR; } /* Get option code. */ omapi_connection_get_uint16 (c, &option_code); link -> imsg_count += 2; if (link -> imsg_count + 2 > link -> imsg_len) { log_error ("FAILOVER: message overflow at length."); return ISC_R_PROTOCOLERROR; } /* Get option length. */ omapi_connection_get_uint16 (c, &option_len); link -> imsg_count += 2; if (link -> imsg_count + option_len > link -> imsg_len) { log_error ("FAILOVER: message overflow at data."); return ISC_R_PROTOCOLERROR; } /* If it's an unknown code, skip over it. */ if (option_code > FTO_MAX) {#if defined (DEBUG_FAILOVER_MESSAGES) log_debug (" option code %d (%s) len %d (not recognized)", option_code, dhcp_failover_option_name (option_code), option_len);#endif omapi_connection_copyout ((unsigned char *)0, c, option_len); link -> imsg_count += option_len; return ISC_R_SUCCESS; } /* If it's the digest, do it now. */ if (ft_options [option_code].type == FT_DIGEST) { link -> imsg_count += option_len; if (link -> imsg_count != link -> imsg_len) { log_error ("FAILOVER: digest not at end of message"); return ISC_R_PROTOCOLERROR; }#if defined (DEBUG_FAILOVER_MESSAGES) log_debug (" option %s len %d", ft_options [option_code].name, option_len);#endif /* For now, just dump it. */ omapi_connection_copyout ((unsigned char *)0, c, option_len); return ISC_R_SUCCESS; } /* Only accept an option once. */ if (link -> imsg -> options_present & ft_options [option_code].bit) { log_error ("FAILOVER: duplicate option %s", ft_options [option_code].name); return ISC_R_PROTOCOLERROR; } /* Make sure the option is appropriate for this type of message. Really, any option is generally allowed for any message, and the cases where this is not true are too complicated to represent in this way - what this code is doing is to just avoid saving the value of an option we don't have any way to use, which allows us to make the failover_message structure smaller. */ if (ft_options [option_code].bit && !(fto_allowed [link -> imsg -> type] & ft_options [option_code].bit)) { omapi_connection_copyout ((unsigned char *)0, c, option_len); link -> imsg_count += option_len; return ISC_R_SUCCESS; } /* Figure out how many elements, how big they are, and where to store them. */ if (ft_options [option_code].num_present) { /* If this option takes a fixed number of elements, we expect the space for them to be preallocated, and we can just read the data in. */ op = ((unsigned char *)link -> imsg) + ft_options [option_code].offset; op_size = ft_sizes [ft_options [option_code].type]; op_count = ft_options [option_code].num_present; if (option_len != op_size * op_count) { log_error ("FAILOVER: option size (%d:%d), option %s", option_len, (ft_sizes [ft_options [option_code].type] * ft_options [option_code].num_present), ft_options [option_code].name); return ISC_R_PROTOCOLERROR; } } else { failover_option_t *fo; /* FT_DDNS* are special - one or two bytes of status followed by the client FQDN. */ if (ft_options [option_code].type == FT_DDNS1 || ft_options [option_code].type == FT_DDNS1) { ddns_fqdn_t *ddns = ((ddns_fqdn_t *) (((char *)link -> imsg) + ft_options [option_code].offset)); op_count = (ft_options [option_code].type == FT_DDNS1 ? 1 : 2); omapi_connection_copyout (&ddns -> codes [0], c, op_count); link -> imsg_count += op_count; if (op_count == 1) ddns -> codes [1] = 0; op_size = 1; op_count = option_len - op_count; ddns -> length = op_count; ddns -> data = dmalloc (op_count, MDL); if (!ddns -> data) { log_error ("FAILOVER: no memory getting%s(%d)", " DNS data ", op_count); /* Actually, NO_MEMORY, but if we lose here we have to drop the connection. */ return ISC_R_PROTOCOLERROR; } omapi_connection_copyout (ddns -> data, c, op_count); goto out; } /* A zero for num_present means that any number of elements can appear, so we have to figure out how many we got from the length of the option, and then fill out a failover_option structure describing the data. */ op_size = ft_sizes [ft_options [option_code].type]; /* Make sure that option data length is a multiple of the size of the data type being sent. */ if (op_size > 1 && option_len % op_size) { log_error ("FAILOVER: option_len %d not %s%d", option_len, "multiple of ", op_size); return ISC_R_PROTOCOLERROR; } op_count = option_len / op_size; fo = ((failover_option_t *) (((char *)link -> imsg) + ft_options [option_code].offset)); fo -> count = op_count; fo -> data = dmalloc (option_len, MDL); if (!fo -> data) { log_error ("FAILOVER: no memory getting %s (%d)", "option data", op_count); return ISC_R_PROTOCOLERROR; } op = fo -> data; } /* For single-byte message values and multi-byte values that don't need swapping, just read them in all at once. */ if (op_size == 1 || ft_options [option_code].type == FT_IPADDR) { omapi_connection_copyout ((unsigned char *)op, c, option_len); link -> imsg_count += option_len; goto out; } /* For values that require swapping, read them in one at a time using routines that swap bytes. */ for (i = 0; i < op_count; i++) { switch (ft_options [option_code].type) { case FT_UINT32: omapi_connection_get_uint32 (c, (u_int32_t *)op); op += 4; link -> imsg_count += 4; break; case FT_UINT16: omapi_connection_get_uint16 (c, (u_int16_t *)op); op += 2; link -> imsg_count += 2; break; default: /* Everything else should have been handled already. */ log_error ("FAILOVER: option %s: bad type %d", ft_options [option_code].name, ft_options [option_code].type); return ISC_R_PROTOCOLERROR; } } out: /* Remember that we got this option. */ link -> imsg -> options_present |= ft_options [option_code].bit; return ISC_R_SUCCESS;}isc_result_t dhcp_failover_link_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value){ if (h -> type != omapi_type_protocol) return ISC_R_INVALIDARG; /* Never valid to set these. */ if (!omapi_ds_strcmp (name, "link-port") || !omapi_ds_strcmp (name, "link-name") || !omapi_ds_strcmp (name, "link-state")) return ISC_R_NOPERM; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND;}isc_result_t dhcp_failover_link_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value){ dhcp_failover_link_t *link; if (h -> type != omapi_type_protocol) return ISC_R_INVALIDARG; link = (dhcp_failover_link_t *)h; if (!omapi_ds_strcmp (name, "link-port")) { return omapi_make_int_value (value, name, (int)link -> peer_port, MDL); } else if (!omapi_ds_strcmp (name, "link-state")) { if (link -> state < 0 || link -> state >= dhcp_flink_state_max) return omapi_make_string_value (value, name, "invalid link state", MDL); return omapi_make_string_value (value, name, dhcp_flink_state_names [link -> state], MDL); } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND;}isc_result_t dhcp_failover_link_destroy (omapi_object_t *h, const char *file, int line){ dhcp_failover_link_t *link; if (h -> type != dhcp_type_failover_link) return ISC_R_INVALIDARG; link = (dhcp_failover_link_t *)h; if (link -> peer_address) option_cache_dereference (&link -> peer_address, file, line); if (link -> imsg) failover_message_dereference (&link -> imsg, file, line); if (link -> state_object) dhcp_failover_state_dereference (&link -> state_object, file, line); return ISC_R_SUCCESS;}/* Write all the published values associated with the object through the specified connection. */isc_result_t dhcp_failover_link_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *l){ dhcp_failover_link_t *link; isc_result_t status; if (l -> type != dhcp_type_failover_link) return ISC_R_INVALIDARG; link = (dhcp_failover_link_t *)l; status = omapi_connection_put_name (c, "link-port"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (int)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, link -> peer_port); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "link-state"); if (status != ISC_R_SUCCESS) return status; if (link -> state < 0 || link -> state >= dhcp_flink_state_max) status = omapi_connection_put_string (c, "invalid link state"); else status = (omapi_connection_put_string (c, dhcp_flink_state_names [link -> state])); if (status != ISC_R_SUCCESS) return status; if (link -> inner && link -> inner -> type -> stuff_values) return (*(link -> inner -> type -> stuff_values)) (c, id, link -> inner); return ISC_R_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -