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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c
          +++ new/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
       23 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  23   24   */
  24   25  
  25   26  #include <sys/types.h>
  26   27  #include <stdlib.h>
  27   28  #include <assert.h>
  28   29  #include <errno.h>
  29   30  #include <locale.h>
  30   31  #include <string.h>
  31   32  #include <unistd.h>
  32   33  #include <signal.h>
  33   34  #include <stdio.h>
  34   35  #include <stdio_ext.h>
  35   36  #include <dhcp_hostconf.h>
  36   37  #include <dhcpagent_ipc.h>
  37   38  #include <dhcpagent_util.h>
  38   39  #include <dhcpmsg.h>
       40 +#include <dhcp_inittab.h>
       41 +#include <dhcp_symbol.h>
  39   42  #include <netinet/dhcp.h>
  40   43  #include <net/route.h>
  41   44  #include <sys/sockio.h>
  42   45  #include <sys/stat.h>
  43   46  #include <stropts.h>
  44   47  #include <fcntl.h>
  45   48  #include <sys/scsi/adapters/iscsi_if.h>
  46   49  
  47   50  #include "async.h"
  48   51  #include "agent.h"
↓ open down ↓ 14 lines elided ↑ open up ↑
  63   66  char                    *class_id;
  64   67  iu_eh_t                 *eh;
  65   68  iu_tq_t                 *tq;
  66   69  pid_t                   grandparent;
  67   70  int                     rtsock_fd;
  68   71  
  69   72  static boolean_t        shutdown_started = B_FALSE;
  70   73  static boolean_t        do_adopt = B_FALSE;
  71   74  static unsigned int     debug_level = 0;
  72   75  static iu_eh_callback_t accept_event, ipc_event, rtsock_event;
       76 +static void dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp,
       77 +                ipc_action_t *iap);
       78 +static DHCP_OPT * dhcp_get_ack_or_state(const dhcp_smach_t *dsmp,
       79 +                const PKT_LIST *plp, uint_t codenum, boolean_t *did_alloc);
  73   80  
  74   81  /*
  75   82   * The ipc_cmd_allowed[] table indicates which IPC commands are allowed in
  76   83   * which states; a non-zero value indicates the command is permitted.
  77   84   *
  78   85   * START is permitted if the state machine is fresh, or if we are in the
  79   86   * process of trying to obtain a lease (as a convenience to save the
  80   87   * administrator from having to do an explicit DROP).  EXTEND, RELEASE, and
  81   88   * GET_TAG require a lease to be obtained in order to make sense.  INFORM is
  82   89   * permitted if the interface is fresh or has an INFORM in progress or
↓ open down ↓ 664 lines elided ↑ open up ↑
 747  754                   * (If so, chaos can result -- e.g., a timer causes us to end
 748  755                   * up in dhcp_selecting() would start acquiring a new lease on
 749  756                   * dsmp while our DHCP_DROP dismantling is ongoing.)
 750  757                   */
 751  758                  cancel_smach_timers(dsmp);
 752  759                  (void) script_start(dsmp, isv6 ? EVENT_DROP6 : EVENT_DROP,
 753  760                      dhcp_drop, NULL, NULL);
 754  761                  break;          /* not an immediate function */
 755  762  
 756  763          case DHCP_EXTEND:
      764 +                dhcp_smach_set_msg_reqhost(dsmp, iap);
 757  765                  (void) dhcp_extending(dsmp);
 758  766                  break;
 759  767  
 760  768          case DHCP_GET_TAG: {
 761  769                  dhcp_optnum_t   optnum;
 762  770                  void            *opt = NULL;
 763  771                  uint_t          optlen;
 764  772                  boolean_t       did_alloc = B_FALSE;
 765  773                  PKT_LIST        *ack = dsmp->dsm_ack;
 766  774                  int             i;
↓ open down ↓ 19 lines elided ↑ open up ↑
 786  794                          for (i = 0; i < dsmp->dsm_pillen; i++) {
 787  795                                  if (dsmp->dsm_pil[i] == optnum.code)
 788  796                                          break;
 789  797                          }
 790  798                          if (i < dsmp->dsm_pillen)
 791  799                                  break;
 792  800                          if (isv6) {
 793  801                                  opt = dhcpv6_pkt_option(ack, NULL, optnum.code,
 794  802                                      NULL);
 795  803                          } else {
 796      -                                if (optnum.code <= DHCP_LAST_OPT)
 797      -                                        opt = ack->opts[optnum.code];
      804 +                                opt = dhcp_get_ack_or_state(dsmp, ack, optnum.code,
      805 +                                    &did_alloc);
 798  806                          }
 799  807                          break;
 800  808  
 801  809                  case DSYM_VENDOR:
 802  810                          if (isv6) {
 803  811                                  dhcpv6_option_t *d6o;
 804  812                                  uint32_t ent;
 805  813  
 806  814                                  /*
 807  815                                   * Look through vendor options to find our
↓ open down ↓ 61 lines elided ↑ open up ↑
 869  877                                          d6o = opt;
 870  878                                          d6o->d6o_code = htons(optnum.code);
 871  879                                          d6o->d6o_len = htons(optnum.size);
 872  880                                          (void) memcpy(d6o + 1, (caddr_t)d6m +
 873  881                                              optnum.code, optnum.size);
 874  882                                  }
 875  883                          } else {
 876  884                                  if (optnum.code + optnum.size > sizeof (PKT))
 877  885                                          break;
 878  886  
 879      -                                /*
 880      -                                 * + 2 to account for option code and length
 881      -                                 * byte
 882      -                                 */
 883      -                                opt = malloc(optnum.size + 2);
      887 +                                opt = malloc(optnum.size + DHCP_OPT_META_LEN);
 884  888                                  if (opt != NULL) {
 885  889                                          DHCP_OPT *v4opt = opt;
 886  890  
 887  891                                          v4opt->len  = optnum.size;
 888  892                                          v4opt->code = optnum.code;
 889  893                                          (void) memcpy(v4opt->value,
 890  894                                              (caddr_t)ack->pkt + optnum.code,
 891  895                                              optnum.size);
 892  896                                  }
 893  897                          }
↓ open down ↓ 4 lines elided ↑ open up ↑
 898  902                          }
 899  903                          did_alloc = B_TRUE;
 900  904                          break;
 901  905  
 902  906                  default:
 903  907                          send_error_reply(iap, DHCP_IPC_E_PROTO);
 904  908                          return;
 905  909                  }
 906  910  
 907  911                  /*
 908      -                 * return the option payload, if there was one.  the "+ 2"
 909      -                 * accounts for the option code number and length byte.
      912 +                 * return the option payload, if there was one.
 910  913                   */
 911  914  
 912  915                  if (opt != NULL) {
 913  916                          if (isv6) {
 914  917                                  dhcpv6_option_t d6ov;
 915  918  
 916  919                                  (void) memcpy(&d6ov, opt, sizeof (d6ov));
 917  920                                  optlen = ntohs(d6ov.d6o_len) + sizeof (d6ov);
 918  921                          } else {
 919      -                                optlen = ((DHCP_OPT *)opt)->len + 2;
      922 +                                optlen = ((DHCP_OPT *)opt)->len + DHCP_OPT_META_LEN;
 920  923                          }
 921  924                          send_data_reply(iap, 0, DHCP_TYPE_OPTION, opt, optlen);
 922  925  
 923  926                          if (did_alloc)
 924  927                                  free(opt);
 925  928                          break;
 926  929                  } else if (ack != dsmp->dsm_orig_ack) {
 927  930                          /*
 928  931                           * There wasn't any definition for the option in the
 929  932                           * current ack, so now retry with the original ack if
↓ open down ↓ 34 lines elided ↑ open up ↑
 964  967                  cancel_smach_timers(dsmp); /* see comment in DHCP_DROP above */
 965  968                  (void) script_start(dsmp, isv6 ? EVENT_RELEASE6 :
 966  969                      EVENT_RELEASE, dhcp_release, "Finished with lease.", NULL);
 967  970                  break;          /* not an immediate function */
 968  971  
 969  972          case DHCP_START: {
 970  973                  PKT_LIST *ack, *oack;
 971  974                  PKT_LIST *plp[2];
 972  975  
 973  976                  deprecate_leases(dsmp);
      977 +                dhcp_smach_set_msg_reqhost(dsmp, iap);
 974  978  
 975  979                  /*
 976  980                   * if we have a valid hostconf lying around, then jump
 977  981                   * into INIT_REBOOT.  if it fails, we'll end up going
 978  982                   * through the whole selecting() procedure again.
 979  983                   */
 980  984  
 981  985                  error = read_hostconf(dsmp->dsm_name, plp, 2, dsmp->dsm_isv6);
 982  986                  ack = error > 0 ? plp[0] : NULL;
 983  987                  oack = error > 1 ? plp[1] : NULL;
↓ open down ↓ 67 lines elided ↑ open up ↑
1051 1055  
1052 1056                  (void) strlcpy(status.if_name, dsmp->dsm_name, LIFNAMSIZ);
1053 1057  
1054 1058                  send_data_reply(iap, 0, DHCP_TYPE_STATUS, &status,
1055 1059                      sizeof (dhcp_status_t));
1056 1060                  break;
1057 1061          }
1058 1062          }
1059 1063  }
1060 1064  
     1065 +/*
     1066 + * dhcp_smach_set_msg_reqhost(): set dsm_msg_reqhost based on the message
     1067 + * content of a DHCP IPC message
     1068 + *
     1069 + *   input: dhcp_smach_t *: the state machine instance;
     1070 + *          ipc_action_t *: the decoded DHCP IPC message;
     1071 + *  output: void
     1072 + */
     1073 +
     1074 +static void
     1075 +dhcp_smach_set_msg_reqhost(dhcp_smach_t *dsmp, ipc_action_t *iap)
     1076 +{
     1077 +        if (dsmp->dsm_msg_reqhost != NULL) {
     1078 +                dhcpmsg(MSG_DEBUG,
     1079 +                    "dhcp_smach_set_msg_reqhost: nullify former value, %s",
     1080 +                    dsmp->dsm_msg_reqhost);
     1081 +                free(dsmp->dsm_msg_reqhost);
     1082 +                dsmp->dsm_msg_reqhost = NULL;
     1083 +        }
     1084 +        free(dsmp->dsm_reqfqdn);
     1085 +        dsmp->dsm_reqfqdn = NULL;
     1086 +
     1087 +        /*
     1088 +         * if a STANDARD/HOSTNAME was sent in the IPC request, then copy that
     1089 +         * value into the state machine data if decoding succeeds. Otherwise,
     1090 +         * log to indicate at what step the decoding stopped.
     1091 +         */
     1092 +
     1093 +        if (dsmp->dsm_isv6) {
     1094 +                dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: ipv6 is not"
     1095 +                    " handled");
     1096 +        } else if (iap->ia_request->data_type != DHCP_TYPE_OPTION) {
     1097 +                dhcpmsg(MSG_DEBUG, "dhcp_smach_set_msg_reqhost: request type %d is"
     1098 +                    " not DHCP_TYPE_OPTION", iap->ia_request->data_type);
     1099 +        } else {
     1100 +                if (iap->ia_request->buffer == NULL
     1101 +                    || iap->ia_request->data_length <= DHCP_OPT_META_LEN) {
     1102 +                        dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:"
     1103 +                            " DHCP_TYPE_OPTION ia_request buffer is NULL (0) or"
     1104 +                            " short (1): %d",
     1105 +                            iap->ia_request->buffer == NULL ? 0 : 1);
     1106 +                } else {
     1107 +                        DHCP_OPT *d4o = (DHCP_OPT *)iap->ia_request->buffer;
     1108 +
     1109 +                        if (d4o->code != CD_HOSTNAME)
     1110 +                        {
     1111 +                                dhcpmsg(MSG_DEBUG,
     1112 +                                    "dhcp_smach_set_msg_reqhost: ignoring DHCPv4"
     1113 +                                    " option %u", d4o->code);
     1114 +                        } else if (iap->ia_request->data_length - DHCP_OPT_META_LEN
     1115 +                            != d4o->len) {
     1116 +                                dhcpmsg(MSG_WARNING, "dhcp_smach_set_msg_reqhost:"
     1117 +                                    " unexpected DHCP_OPT buffer length %u for CD_HOSTNAME"
     1118 +                                    " option length %u", iap->ia_request->data_length,
     1119 +                                    d4o->len);
     1120 +                        } else {
     1121 +
     1122 +                                dhcp_symbol_t *entry = inittab_getbycode(ITAB_CAT_STANDARD,
     1123 +                                    ITAB_CONS_INFO, CD_HOSTNAME);
     1124 +                                if (entry == NULL) {
     1125 +                                        dhcpmsg(MSG_WARNING,
     1126 +                                            "dhcp_smach_set_msg_reqhost: error getting"
     1127 +                                            " ITAB_CAT_STANDARD ITAB_CONS_INFO"
     1128 +                                            " CD_HOSTNAME entry");
     1129 +                                } else {
     1130 +                                        char *value = inittab_decode(entry, d4o->value,
     1131 +                                            d4o->len, /* just_payload */ B_TRUE);
     1132 +                                        if (value == NULL) {
     1133 +                                                dhcpmsg(MSG_WARNING,
     1134 +                                                    "dhcp_smach_set_msg_reqhost: error decoding"
     1135 +                                                    " CD_HOSTNAME value from DHCP_OPT");
     1136 +                                        } else {
     1137 +                                                dhcpmsg(MSG_DEBUG,
     1138 +                                                    "dhcp_smach_set_msg_reqhost: host %s", value);
     1139 +                                                free(dsmp->dsm_msg_reqhost);
     1140 +                                                dsmp->dsm_msg_reqhost = value;
     1141 +                                        }
     1142 +                                        free(entry);
     1143 +                                        entry = NULL;
     1144 +                                }
     1145 +                        }
     1146 +                }
     1147 +        }
     1148 +}
     1149 +
     1150 +/*
     1151 + * dhcp_get_ack_or_state(): get a v4 option from the ACK or from the state
     1152 + * machine state for certain codes that are not ACKed (e.g., CD_CLIENT_ID)
     1153 + *
     1154 + *   input: dhcp_smach_t *: the state machine instance;
     1155 + *          PKT_LIST *: the decoded DHCP IPC message;
     1156 + *          uint_t: the DHCP client option code;
     1157 + *          boolean_t *: a pointer to a value that will be set to B_TRUE if
     1158 + *              the return value must be freed (or else set to B_FALSE);
     1159 + *  output: the option if found or else NULL.
     1160 + */
     1161 +
     1162 +/* ARGSUSED */
     1163 +static DHCP_OPT *
     1164 +dhcp_get_ack_or_state(const dhcp_smach_t *dsmp, const PKT_LIST *plp,
     1165 +        uint_t codenum, boolean_t *did_alloc)
     1166 +{
     1167 +        DHCP_OPT *opt;
     1168 +
     1169 +        *did_alloc = B_FALSE;
     1170 +
     1171 +        if (codenum > DHCP_LAST_OPT)
     1172 +                return NULL;
     1173 +
     1174 +        /* check the ACK first for all codes */
     1175 +        opt = plp->opts[codenum];
     1176 +        if (opt != NULL)
     1177 +                return opt;
     1178 +
     1179 +        /* check the machine state also for certain codes */
     1180 +        switch (codenum) {
     1181 +        case CD_CLIENT_ID:
     1182 +                /*
     1183 +                 * CD_CLIENT_ID is not sent in an ACK, but it's possibly available
     1184 +                 * from the state machine data
     1185 +                 */
     1186 +
     1187 +                if (dsmp->dsm_cidlen > 0) {
     1188 +                        if ((opt = malloc(dsmp->dsm_cidlen + DHCP_OPT_META_LEN))
     1189 +                            != NULL) {
     1190 +                                *did_alloc = B_TRUE;
     1191 +                                (void) encode_dhcp_opt(opt, B_FALSE /* is IPv6 */,
     1192 +                                    CD_CLIENT_ID, dsmp->dsm_cid, dsmp->dsm_cidlen);
     1193 +                        }
     1194 +                }
     1195 +                break;
     1196 +        default:
     1197 +                break;
     1198 +        }
     1199 +        return (opt);
     1200 +}
     1201 +
1061 1202  /*
1062 1203   * check_rtm_addr(): determine if routing socket message matches interface
1063 1204   *                   address
1064 1205   *
1065 1206   *   input: const struct if_msghdr *: pointer to routing socket message
1066 1207   *          int: routing socket message length
1067 1208   *          boolean_t: set to B_TRUE if IPv6
1068 1209   *          const in6_addr_t *: pointer to IP address
1069 1210   *  output: boolean_t: B_TRUE if address is a match
1070 1211   */
↓ open down ↓ 469 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX