options.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * options.c -- DHCP server option packet tools
  4. * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
  5. */
  6. #include "common.h"
  7. #include "dhcpd.h"
  8. #include "options.h"
  9. /* Supported options are easily added here */
  10. const struct dhcp_option dhcp_options[] = {
  11. /* flags code */
  12. { OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */
  13. { OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */
  14. { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */
  15. { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */
  16. { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */
  17. { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */
  18. { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */
  19. { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */
  20. { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */
  21. { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */
  22. { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */
  23. { OPTION_STRING | OPTION_LIST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */
  24. { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */
  25. { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */
  26. { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
  27. { OPTION_U16 , 0x1a }, /* DHCP_MTU */
  28. { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
  29. { OPTION_STRING , 0x28 }, /* nisdomain */
  30. { OPTION_IP | OPTION_LIST , 0x29 }, /* nissrv */
  31. { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
  32. { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */
  33. { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */
  34. { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */
  35. { OPTION_U8 , 0x35 }, /* dhcptype */
  36. { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */
  37. { OPTION_STRING , 0x38 }, /* DHCP_MESSAGE */
  38. { OPTION_STRING , 0x3C }, /* DHCP_VENDOR */
  39. { OPTION_STRING , 0x3D }, /* DHCP_CLIENT_ID */
  40. { OPTION_STRING , 0x42 }, /* tftp */
  41. { OPTION_STRING , 0x43 }, /* bootfile */
  42. { OPTION_STRING , 0x4D }, /* userclass */
  43. #if ENABLE_FEATURE_UDHCP_RFC3397
  44. { OPTION_STR1035 | OPTION_LIST , 0x77 }, /* search */
  45. #endif
  46. /* MSIE's "Web Proxy Autodiscovery Protocol" support */
  47. { OPTION_STRING , 0xfc }, /* wpad */
  48. /* Options below have no match in dhcp_option_strings[],
  49. * are not passed to dhcpc scripts, and cannot be specified
  50. * with "option XXX YYY" syntax in dhcpd config file. */
  51. { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */
  52. { } /* zeroed terminating entry */
  53. };
  54. /* Used for converting options from incoming packets to env variables
  55. * for udhcpc stript */
  56. /* Must match dhcp_options[] order */
  57. const char dhcp_option_strings[] ALIGN1 =
  58. "subnet" "\0" /* DHCP_SUBNET */
  59. "timezone" "\0" /* DHCP_TIME_OFFSET */
  60. "router" "\0" /* DHCP_ROUTER */
  61. "timesrv" "\0" /* DHCP_TIME_SERVER */
  62. "namesrv" "\0" /* DHCP_NAME_SERVER */
  63. "dns" "\0" /* DHCP_DNS_SERVER */
  64. "logsrv" "\0" /* DHCP_LOG_SERVER */
  65. "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */
  66. "lprsrv" "\0" /* DHCP_LPR_SERVER */
  67. "hostname" "\0" /* DHCP_HOST_NAME */
  68. "bootsize" "\0" /* DHCP_BOOT_SIZE */
  69. "domain" "\0" /* DHCP_DOMAIN_NAME */
  70. "swapsrv" "\0" /* DHCP_SWAP_SERVER */
  71. "rootpath" "\0" /* DHCP_ROOT_PATH */
  72. "ipttl" "\0" /* DHCP_IP_TTL */
  73. "mtu" "\0" /* DHCP_MTU */
  74. "broadcast" "\0" /* DHCP_BROADCAST */
  75. "nisdomain" "\0" /* */
  76. "nissrv" "\0" /* */
  77. "ntpsrv" "\0" /* DHCP_NTP_SERVER */
  78. "wins" "\0" /* DHCP_WINS_SERVER */
  79. "requestip" "\0" /* DHCP_REQUESTED_IP */
  80. "lease" "\0" /* DHCP_LEASE_TIME */
  81. "dhcptype" "\0" /* */
  82. "serverid" "\0" /* DHCP_SERVER_ID */
  83. "message" "\0" /* DHCP_MESSAGE */
  84. "vendorclass" "\0" /* DHCP_VENDOR */
  85. "clientid" "\0" /* DHCP_CLIENT_ID */
  86. "tftp" "\0"
  87. "bootfile" "\0"
  88. "userclass" "\0"
  89. #if ENABLE_FEATURE_UDHCP_RFC3397
  90. "search" "\0"
  91. #endif
  92. /* MSIE's "Web Proxy Autodiscovery Protocol" support */
  93. "wpad" "\0"
  94. ;
  95. /* Lengths of the different option types */
  96. const uint8_t dhcp_option_lengths[] ALIGN1 = {
  97. [OPTION_IP] = 4,
  98. [OPTION_IP_PAIR] = 8,
  99. [OPTION_BOOLEAN] = 1,
  100. [OPTION_STRING] = 1,
  101. #if ENABLE_FEATURE_UDHCP_RFC3397
  102. [OPTION_STR1035] = 1,
  103. #endif
  104. [OPTION_U8] = 1,
  105. [OPTION_U16] = 2,
  106. [OPTION_S16] = 2,
  107. [OPTION_U32] = 4,
  108. [OPTION_S32] = 4
  109. };
  110. /* get an option with bounds checking (warning, not aligned). */
  111. uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code)
  112. {
  113. int i, length;
  114. uint8_t *optionptr;
  115. int over = 0;
  116. int curr = OPTION_FIELD;
  117. optionptr = packet->options;
  118. i = 0;
  119. length = sizeof(packet->options);
  120. while (1) {
  121. if (i >= length) {
  122. bb_error_msg("bogus packet, option fields too long");
  123. return NULL;
  124. }
  125. if (optionptr[i + OPT_CODE] == code) {
  126. if (i + 1 + optionptr[i + OPT_LEN] >= length) {
  127. bb_error_msg("bogus packet, option fields too long");
  128. return NULL;
  129. }
  130. return optionptr + i + 2;
  131. }
  132. switch (optionptr[i + OPT_CODE]) {
  133. case DHCP_PADDING:
  134. i++;
  135. break;
  136. case DHCP_OPTION_OVER:
  137. if (i + 1 + optionptr[i + OPT_LEN] >= length) {
  138. bb_error_msg("bogus packet, option fields too long");
  139. return NULL;
  140. }
  141. over = optionptr[i + 3];
  142. i += optionptr[OPT_LEN] + 2;
  143. break;
  144. case DHCP_END:
  145. if (curr == OPTION_FIELD && (over & FILE_FIELD)) {
  146. optionptr = packet->file;
  147. i = 0;
  148. length = sizeof(packet->file);
  149. curr = FILE_FIELD;
  150. } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) {
  151. optionptr = packet->sname;
  152. i = 0;
  153. length = sizeof(packet->sname);
  154. curr = SNAME_FIELD;
  155. } else
  156. return NULL;
  157. break;
  158. default:
  159. i += optionptr[OPT_LEN + i] + 2;
  160. }
  161. }
  162. return NULL;
  163. }
  164. /* return the position of the 'end' option (no bounds checking) */
  165. int FAST_FUNC end_option(uint8_t *optionptr)
  166. {
  167. int i = 0;
  168. while (optionptr[i] != DHCP_END) {
  169. if (optionptr[i] == DHCP_PADDING)
  170. i++;
  171. else
  172. i += optionptr[i + OPT_LEN] + 2;
  173. }
  174. return i;
  175. }
  176. /* add an option string to the options (an option string contains an option code,
  177. * length, then data) */
  178. int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string)
  179. {
  180. int end = end_option(optionptr);
  181. /* end position + string length + option code/length + end option */
  182. if (end + string[OPT_LEN] + 2 + 1 >= DHCP_OPTIONS_BUFSIZE) {
  183. bb_error_msg("option 0x%02x did not fit into the packet",
  184. string[OPT_CODE]);
  185. return 0;
  186. }
  187. DEBUG("adding option 0x%02x", string[OPT_CODE]);
  188. memcpy(optionptr + end, string, string[OPT_LEN] + 2);
  189. optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
  190. return string[OPT_LEN] + 2;
  191. }
  192. /* add a one to four byte option to a packet */
  193. int FAST_FUNC add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data)
  194. {
  195. const struct dhcp_option *dh;
  196. for (dh = dhcp_options; dh->code; dh++) {
  197. if (dh->code == code) {
  198. uint8_t option[6], len;
  199. option[OPT_CODE] = code;
  200. len = dhcp_option_lengths[dh->flags & TYPE_MASK];
  201. option[OPT_LEN] = len;
  202. if (BB_BIG_ENDIAN)
  203. data <<= 8 * (4 - len);
  204. /* This memcpy is for processors which can't
  205. * handle a simple unaligned 32-bit assignment */
  206. memcpy(&option[OPT_DATA], &data, 4);
  207. return add_option_string(optionptr, option);
  208. }
  209. }
  210. bb_error_msg("cannot add option 0x%02x", code);
  211. return 0;
  212. }