/* * Function: dhcpol_parse_packet * * Purpose: * Parse the option areas in the DHCP packet. * Verifies that the packet has the right magic number, * then parses and accumulates the option areas. * First the pkt->dp_options is parsed. If that contains * the overload option, it parses pkt->dp_file if specified, * then parses pkt->dp_sname if specified. */ boolean_t dhcpol_parse_packet(dhcpol_t * options, struct dhcp * pkt, int len, unsigned char * err) { char rfc_magic[4] = RFC_OPTIONS_MAGIC; dhcpol_init(options); /* make sure it's empty */ if (err) err[0] = '\0'; if (len < (sizeof(*pkt) + RFC_MAGIC_SIZE)) { if (err) { sprintf(err, "packet is too short: %d < %d", len, (int)sizeof(*pkt) + RFC_MAGIC_SIZE); } return (FALSE); } if (bcmp(pkt->dp_options, rfc_magic, RFC_MAGIC_SIZE)) { if (err) sprintf(err, "missing magic number"); return (FALSE); } if (dhcpol_parse_buffer(options, pkt->dp_options + RFC_MAGIC_SIZE, len - sizeof(*pkt) - RFC_MAGIC_SIZE, err) == FALSE) return (FALSE); { /* get overloaded options */ unsigned char * overload; int overload_len; overload = (unsigned char *) dhcpol_find(options, dhcptag_option_overload_e, &overload_len, NULL); if (overload && overload_len == 1) { /* has overloaded options */ dhcpol_t extra; dhcpol_init(&extra); if (*overload == DHCP_OVERLOAD_FILE || *overload == DHCP_OVERLOAD_BOTH) { if (dhcpol_parse_buffer(&extra, pkt->dp_file, sizeof(pkt->dp_file), NULL)) { dhcpol_concat(options, &extra); dhcpol_free(&extra); } } if (*overload == DHCP_OVERLOAD_SNAME || *overload == DHCP_OVERLOAD_BOTH) { if (dhcpol_parse_buffer(&extra, pkt->dp_sname, sizeof(pkt->dp_sname), NULL)) { dhcpol_concat(options, &extra); dhcpol_free(&extra); } } } } return (TRUE); }
int main() { int i; dhcpol_t options; char error[256]; struct dhcp * pkt = (struct dhcp *)buf; dhcpol_init(&options); for (i = 0; tests[i].name; i++) { printf("\nTest %d: ", i); bcopy(tests[i].data, pkt->dp_options, tests[i].len); if (dhcpol_parse_packet(&options, pkt, sizeof(*pkt) + tests[i].len, error) != tests[i].result) { printf("test '%s' FAILED\n", tests[i].name); if (tests[i].result == TRUE) { printf("error message returned was %s\n", error); } } else { printf("test '%s' PASSED\n", tests[i].name); if (tests[i].result == FALSE) { printf("error message returned was %s\n", error); } } dhcpol_free(&options); } exit(0); }
/* * Function: dhcpol_parse_vendor * * Purpose: * Given a set of options, find the vendor specific option(s) * and parse all of them into a single option list. * * Return value: * TRUE if vendor specific options existed and were parsed succesfully, * FALSE otherwise. */ boolean_t dhcpol_parse_vendor(dhcpol_t * vendor, dhcpol_t * options, unsigned char * err) { dhcpol_t extra; boolean_t ret = FALSE; int start = 0; if (err) err[0] = '\0'; dhcpol_init(vendor); dhcpol_init(&extra); for (;;) { void * data; int len; data = dhcpol_find(options, dhcptag_vendor_specific_e, &len, &start); if (data == NULL) { break; /* out of for */ } if (dhcpol_parse_buffer(&extra, data, len, err) == FALSE) { goto failed; } if (dhcpol_concat(vendor, &extra) == FALSE) { if (err) sprintf(err, "dhcpol_concat() failed at %d\n", start); goto failed; } dhcpol_free(&extra); ret = TRUE; } if (ret == FALSE) { if (err) strcpy(err, "missing vendor specific options"); } return (ret); failed: dhcpol_free(vendor); dhcpol_free(&extra); return (FALSE); }
PRIVATE_EXTERN void bsdp_print_packet(struct dhcp * pkt, int length, int options_only) { dhcpo_err_str_t err; int i; dhcpol_t options; dhcpol_t vendor_options; dhcpol_init(&options); dhcpol_init(&vendor_options); if (options_only == 0) { dhcp_packet_print(pkt, length); } if (dhcpol_parse_packet(&options, pkt, length, &err) == FALSE) { fprintf(stderr, "packet did not parse, %s\n", err.str); return; } if (dhcpol_parse_vendor(&vendor_options, &options, &err) == FALSE) { fprintf(stderr, "vendor options did not parse, %s\n", err.str); goto done; } printf("BSDP Options count is %d\n", dhcpol_count(&vendor_options)); for (i = 0; i < dhcpol_count(&vendor_options); i++) { u_int8_t code; u_int8_t * opt = dhcpol_element(&vendor_options, i); u_int8_t len; code = opt[TAG_OFFSET]; len = opt[LEN_OFFSET]; printf("%s: ", bsdptag_name(code)); if (code == bsdptag_message_type_e) { printf("%s (", bsdp_msgtype_names(opt[OPTION_OFFSET])); dhcptype_print(bsdptag_type(code), opt + OPTION_OFFSET, len); printf(")\n"); } else { dhcptype_print(bsdptag_type(code), opt + OPTION_OFFSET, len); printf("\n"); } } done: dhcpol_free(&options); dhcpol_free(&vendor_options); return; }
/* * Function: dhcpol_parse_buffer * * Purpose: * Parse the given buffer into DHCP options, returning the * list of option pointers in the given dhcpol_t. * Parsing continues until we hit the end of the buffer or * the end tag. */ boolean_t dhcpol_parse_buffer(dhcpol_t * list, void * buffer, int length, unsigned char * err) { int len; unsigned char * scan; unsigned char tag; if (err) err[0] = '\0'; dhcpol_init(list); len = length; tag = dhcptag_pad_e; for (scan = (unsigned char *)buffer; tag != dhcptag_end_e && len > 0; ) { tag = scan[DHCP_TAG_OFFSET]; switch (tag) { case dhcptag_end_e: dhcpol_add(list, scan); /* remember that it was terminated */ scan++; len--; break; case dhcptag_pad_e: /* ignore pad */ scan++; len--; break; default: { unsigned char option_len = scan[DHCP_LEN_OFFSET]; dhcpol_add(list, scan); len -= (option_len + 2); scan += (option_len + 2); break; } } } if (len < 0) { /* ran off the end */ if (err) sprintf(err, "parse failed near tag %d", tag); dhcpol_free(list); return (FALSE); } return (TRUE); }
void dhcp_packet_print_cfstr(CFMutableStringRef str, struct dhcp * dp, int pkt_len) { int i; int j; int len; if (pkt_len < sizeof(struct dhcp)) { STRING_APPEND(str, "Packet is too short %d < %d\n", pkt_len, (int)sizeof(struct dhcp)); return; } STRING_APPEND(str, "op = "); if (dp->dp_op == BOOTREQUEST) { STRING_APPEND(str, "BOOTREQUEST\n"); } else if (dp->dp_op == BOOTREPLY) { STRING_APPEND(str, "BOOTREPLY\n"); } else { i = dp->dp_op; STRING_APPEND(str, "OP(%d)\n", i); } i = dp->dp_htype; STRING_APPEND(str, "htype = %d\n", i); STRING_APPEND(str, "flags = %x\n", ntohs(dp->dp_flags)); len = dp->dp_hlen; STRING_APPEND(str, "hlen = %d\n", len); i = dp->dp_hops; STRING_APPEND(str, "hops = %d\n", i); STRING_APPEND(str, "xid = %lu\n", (u_long)ntohl(dp->dp_xid)); STRING_APPEND(str, "secs = %hu\n", ntohs(dp->dp_secs)); STRING_APPEND(str, "ciaddr = %s\n", inet_ntoa(dp->dp_ciaddr)); STRING_APPEND(str, "yiaddr = %s\n", inet_ntoa(dp->dp_yiaddr)); STRING_APPEND(str, "siaddr = %s\n", inet_ntoa(dp->dp_siaddr)); STRING_APPEND(str, "giaddr = %s\n", inet_ntoa(dp->dp_giaddr)); STRING_APPEND(str, "chaddr = "); for (j = 0; j < len; j++) { i = dp->dp_chaddr[j]; STRING_APPEND(str, "%0x", i); if (j < (len - 1)) STRING_APPEND(str, ":"); } STRING_APPEND(str, "\n"); STRING_APPEND(str, "sname = %s\n", dp->dp_sname); STRING_APPEND(str, "file = %s\n", dp->dp_file); { dhcpol_t t; dhcpol_init(&t); if (dhcpol_parse_packet(&t, dp, pkt_len, NULL)) { STRING_APPEND(str, "options:\n"); dhcpol_print_cfstr(str, &t); } dhcpol_free(&t); } return; }