Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.

*** 18,27 **** --- 18,28 ---- * * CDDL HEADER END */ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>. */ #include <sys/types.h> #include <stdlib.h> #include <assert.h>
*** 34,43 **** --- 35,46 ---- #include <stdio_ext.h> #include <dhcp_hostconf.h> #include <dhcpagent_ipc.h> #include <dhcpagent_util.h> #include <dhcpmsg.h> + #include <dhcp_inittab.h> + #include <dhcp_symbol.h> #include <netinet/dhcp.h> #include <net/route.h> #include <sys/sockio.h> #include <sys/stat.h> #include <stropts.h>
*** 68,77 **** --- 71,84 ---- static boolean_t shutdown_started = B_FALSE; static boolean_t do_adopt = B_FALSE; static unsigned int debug_level = 0; static iu_eh_callback_t accept_event, ipc_event, rtsock_event; + static void dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp, + ipc_action_t *iap); + static DHCP_OPT * dhcp_get_ack_or_state(const dhcp_smach_t *dsmp, + const PKT_LIST *plp, uint_t codenum, boolean_t *did_alloc); /* * The ipc_cmd_allowed[] table indicates which IPC commands are allowed in * which states; a non-zero value indicates the command is permitted. *
*** 752,761 **** --- 759,769 ---- (void) script_start(dsmp, isv6 ? EVENT_DROP6 : EVENT_DROP, dhcp_drop, NULL, NULL); break; /* not an immediate function */ case DHCP_EXTEND: + dhcp_smach_set_msg_reqhost(dsmp, iap); (void) dhcp_extending(dsmp); break; case DHCP_GET_TAG: { dhcp_optnum_t optnum;
*** 791,802 **** break; if (isv6) { opt = dhcpv6_pkt_option(ack, NULL, optnum.code, NULL); } else { ! if (optnum.code <= DHCP_LAST_OPT) ! opt = ack->opts[optnum.code]; } break; case DSYM_VENDOR: if (isv6) { --- 799,810 ---- break; if (isv6) { opt = dhcpv6_pkt_option(ack, NULL, optnum.code, NULL); } else { ! opt = dhcp_get_ack_or_state(dsmp, ack, optnum.code, ! &did_alloc); } break; case DSYM_VENDOR: if (isv6) {
*** 874,888 **** } } else { if (optnum.code + optnum.size > sizeof (PKT)) break; ! /* ! * + 2 to account for option code and length ! * byte ! */ ! opt = malloc(optnum.size + 2); if (opt != NULL) { DHCP_OPT *v4opt = opt; v4opt->len = optnum.size; v4opt->code = optnum.code; --- 882,892 ---- } } else { if (optnum.code + optnum.size > sizeof (PKT)) break; ! opt = malloc(optnum.size + DHCP_OPT_META_LEN); if (opt != NULL) { DHCP_OPT *v4opt = opt; v4opt->len = optnum.size; v4opt->code = optnum.code;
*** 903,924 **** send_error_reply(iap, DHCP_IPC_E_PROTO); return; } /* ! * return the option payload, if there was one. the "+ 2" ! * accounts for the option code number and length byte. */ if (opt != NULL) { if (isv6) { dhcpv6_option_t d6ov; (void) memcpy(&d6ov, opt, sizeof (d6ov)); optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov); } else { ! optlen = ((DHCP_OPT *)opt)->len + 2; } send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen); if (did_alloc) free(opt); --- 907,927 ---- send_error_reply(iap, DHCP_IPC_E_PROTO); return; } /* ! * return the option payload, if there was one. */ if (opt != NULL) { if (isv6) { dhcpv6_option_t d6ov; (void) memcpy(&d6ov, opt, sizeof (d6ov)); optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov); } else { ! optlen = ((DHCP_OPT *)opt)->len + DHCP_OPT_META_LEN; } send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen); if (did_alloc) free(opt);
*** 969,978 **** --- 972,982 ---- case DHCP_START: { PKT_LIST *ack, *oack; PKT_LIST *plp[2]; deprecate_leases(dsmp); + dhcp_smach_set_msg_reqhost(dsmp, iap); /* * if we have a valid hostconf lying around, then jump * into INIT_REBOOT. if it fails, we'll end up going * through the whole selecting() procedure again.
*** 1056,1065 **** --- 1060,1206 ---- break; } } } + /* + * dhcp_smach_set_msg_reqhost(): set dsm_msg_reqhost based on the message + * content of a DHCP IPC message + * + * input: dhcp_smach_t *: the state machine instance; + * ipc_action_t *: the decoded DHCP IPC message; + * output: void + */ + + static void + dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp, ipc_action_t *iap) + { + if (dsmp->dsm_msg_reqhost != NULL) { + dhcpmsg(MSG_DEBUG, + "dhcp_smach_set_msg_reqhost: nullify former value, %s", + dsmp->dsm_msg_reqhost); + free(dsmp->dsm_msg_reqhost); + dsmp->dsm_msg_reqhost = NULL; + } + free(dsmp->dsm_reqfqdn); + dsmp->dsm_reqfqdn = NULL; + + /* + * if a STANDARD/HOSTNAME was sent in the IPC request, then copy that + * value into the state machine data if decoding succeeds. Otherwise, + * log to indicate at what step the decoding stopped. + */ + + if (dsmp->dsm_isv6) { + dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: ipv6 is not" + " handled"); + } else if (iap->ia_request->data_type != DHCP_TYPE_OPTION) { + dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: request type %d is" + " not DHCP_TYPE_OPTION", iap->ia_request->data_type); + } else { + if (iap->ia_request->buffer == NULL + || iap->ia_request->data_length <= DHCP_OPT_META_LEN) { + dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:" + " DHCP_TYPE_OPTION ia_request buffer is NULL (0) or" + " short (1): %d", + iap->ia_request->buffer == NULL ? 0 : 1); + } else { + DHCP_OPT *d4o = (DHCP_OPT *)iap->ia_request->buffer; + + if (d4o->code != CD_HOSTNAME) + { + dhcpmsg(MSG_DEBUG, + "dhcp_smach_set_msg_reqhost: ignoring DHCPv4" + " option %u", d4o->code); + } else if (iap->ia_request->data_length - DHCP_OPT_META_LEN + != d4o->len) { + dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:" + " unexpected DHCP_OPT buffer length %u for CD_HOSTNAME" + " option length %u", iap->ia_request->data_length, + d4o->len); + } else { + + dhcp_symbol_t *entry = inittab_getbycode(ITAB_CAT_STANDARD, + ITAB_CONS_INFO, CD_HOSTNAME); + if (entry == NULL) { + dhcpmsg(MSG_WARNING, + "dhcp_smach_set_msg_reqhost: error getting" + " ITAB_CAT_STANDARD ITAB_CONS_INFO" + " CD_HOSTNAME entry"); + } else { + char *value = inittab_decode(entry, d4o->value, + d4o->len, /* just_payload */ B_TRUE); + if (value == NULL) { + dhcpmsg(MSG_WARNING, + "dhcp_smach_set_msg_reqhost: error decoding" + " CD_HOSTNAME value from DHCP_OPT"); + } else { + dhcpmsg(MSG_DEBUG, + "dhcp_smach_set_msg_reqhost: host %s", value); + free(dsmp->dsm_msg_reqhost); + dsmp->dsm_msg_reqhost = value; + } + free(entry); + entry = NULL; + } + } + } + } + } + + /* + * dhcp_get_ack_or_state(): get a v4 option from the ACK or from the state + * machine state for certain codes that are not ACKed (e.g., CD_CLIENT_ID) + * + * input: dhcp_smach_t *: the state machine instance; + * PKT_LIST *: the decoded DHCP IPC message; + * uint_t: the DHCP client option code; + * boolean_t *: a pointer to a value that will be set to B_TRUE if + * the return value must be freed (or else set to B_FALSE); + * output: the option if found or else NULL. + */ + + /* ARGSUSED */ + static DHCP_OPT * + dhcp_get_ack_or_state(const dhcp_smach_t *dsmp, const PKT_LIST *plp, + uint_t codenum, boolean_t *did_alloc) + { + DHCP_OPT *opt; + + *did_alloc = B_FALSE; + + if (codenum > DHCP_LAST_OPT) + return NULL; + + /* check the ACK first for all codes */ + opt = plp->opts[codenum]; + if (opt != NULL) + return opt; + + /* check the machine state also for certain codes */ + switch (codenum) { + case CD_CLIENT_ID: + /* + * CD_CLIENT_ID is not sent in an ACK, but it's possibly available + * from the state machine data + */ + + if (dsmp->dsm_cidlen > 0) { + if ((opt = malloc(dsmp->dsm_cidlen + DHCP_OPT_META_LEN)) + != NULL) { + *did_alloc = B_TRUE; + (void) encode_dhcp_opt(opt, B_FALSE /* is IPv6 */, + CD_CLIENT_ID, dsmp->dsm_cid, dsmp->dsm_cidlen); + } + } + break; + default: + break; + } + return (opt); + } + /* * check_rtm_addr(): determine if routing socket message matches interface * address * * input: const struct if_msghdr *: pointer to routing socket message