[systemd-devel] [PATCH 08/28] dhcp: Add tests for DHCP options, file and sname fields
Zbigniew Jędrzejewski-Szmek
zbyszek at in.waw.pl
Wed Nov 13 18:08:59 PST 2013
On Wed, Nov 13, 2013 at 11:22:36PM +0200, Patrik Flykt wrote:
> Add a structure describing the DHCP file, sname and trailing options
> fields. Create a messge holding these fields and call the internal
> option parsing function.
>
> In the test callback function verify that only regular options are
> passed and figure out which part of the DHCP message is the one that
> is being processed. As the test program knows the full contents of
> the test options in the test structure, skip all non-regular fields
> and verify that the option provided to the callback indeed is the
> one expected. Check also if non-regular option fields are to be
> ignored in the end of the option field as the callback is not called
> again and the final check when the whole message has been processed
> needs to be successful.
>
> Add a boolean flag for pretty-printing, anticipate there will be a
> nice option to toggle it in the future.
> ---
> src/dhcp/test-dhcp-option.c | 258 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 258 insertions(+)
>
> diff --git a/src/dhcp/test-dhcp-option.c b/src/dhcp/test-dhcp-option.c
> index 9302fd6..a2b79ce 100644
> --- a/src/dhcp/test-dhcp-option.c
> +++ b/src/dhcp/test-dhcp-option.c
> @@ -10,6 +10,68 @@
> #include "protocol.h"
> #include "internal.h"
>
> +struct option_desc {
> + uint8_t sname[64];
> + int snamelen;
> + uint8_t file[128];
> + int filelen;
> + uint8_t options[128];
> + int len;
> + bool success;
> + int filepos;
> + int snamepos;
> + int pos;
> +};
> +
> +static bool verbose = false;
> +
> +static struct option_desc option_tests[] = {
> + { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, },
> + { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0,
> + DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, },
> + { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, },
> + { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8,
> + 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01,
> + 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0,
> + 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00,
> + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
> + 40, true, },
> + { {}, 0, {}, 0, { DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER,
> + 42, 3, 0, 0, 0 }, 8, true, },
> + { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, },
> +
> + { {}, 0,
> + { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8,
> + { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, },
> +
> + { { 1, 4, 1, 2, 3, 4, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9,
> + { 222, 3, 1, 2, 3 }, 5,
> + { DHCP_OPTION_OVERLOAD, 1,
> + DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
> +};
> +
> +static const char *dhcp_type(int type)
> +{
> + switch(type) {
> + case DHCP_DISCOVER:
> + return "DHCPDISCOVER";
> + case DHCP_OFFER:
> + return "DHCPOFFER";
> + case DHCP_REQUEST:
> + return "DHCPREQUEST";
> + case DHCP_DECLINE:
> + return "DHCPDECLINE";
> + case DHCP_ACK:
> + return "DHCPACK";
> + case DHCP_NAK:
> + return "DHCPNAK";
> + case DHCP_RELEASE:
> + return "DHCPRELEASE";
> + default:
> + return "unknown";
> + }
> +}
> +
> static void test_invalid_buffer_length(void)
> {
> DHCPMessage message;
> @@ -43,10 +105,206 @@ static void test_cookie(void)
> free(message);
> }
>
> +static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
> + uint8_t *file, uint8_t filelen,
> + uint8_t *sname, uint8_t snamelen)
> +{
> + DHCPMessage *message;
> + int len = sizeof(DHCPMessage) + 4 + optlen;
> + uint8_t *opt;
> +
> + message = malloc0(len);
> + opt = (uint8_t *)(message + 1);
> +
> + opt[0] = 99;
> + opt[1] = 130;
> + opt[2] = 83;
> + opt[3] = 99;
> +
> + if (options && optlen)
> + memcpy(&opt[4], options, optlen);
> +
> + if (file && filelen <= 128)
> + memcpy(&message->file, file, filelen);
> +
> + if (sname && snamelen <= 64)
> + memcpy(&message->sname, sname, snamelen);
> +
> + return message;
> +}
> +
> +static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen)
> +{
> + while (*descpos < *desclen) {
> + switch(descoption[*descpos]) {
> + case DHCP_OPTION_PAD:
> + *descpos += 1;
> + break;
> +
> + case DHCP_OPTION_MESSAGE_TYPE:
> + case DHCP_OPTION_OVERLOAD:
> + *descpos += 3;
> + break;
> +
> + default:
> + return;
> + }
> + }
> +}
> +
> +static int test_options_cb(uint8_t code, uint8_t len, uint8_t *option,
> + void *user_data)
> +{
> + struct option_desc *desc = user_data;
> + uint8_t *descoption = NULL;
> + int *desclen = NULL, *descpos = NULL;
> + uint8_t optcode = 0;
> + uint8_t optlen = 0;
> + uint8_t i;
> +
> + assert((!desc && !code && !len) || desc);
> +
> + if (!desc)
> + return -EINVAL;
> +
> + assert(code != DHCP_OPTION_PAD);
> + assert(code != DHCP_OPTION_END);
> + assert(code != DHCP_OPTION_MESSAGE_TYPE);
> + assert(code != DHCP_OPTION_OVERLOAD);
> +
> + while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) {
> +
> + if (desc->pos >= 0) {
> + descoption = &desc->options[0];
> + desclen = &desc->len;
> + descpos = &desc->pos;
> + } else if (desc->filepos >= 0) {
> + descoption = &desc->file[0];
> + desclen = &desc->filelen;
> + descpos = &desc->filepos;
> + } else if (desc->snamepos >= 0) {
> + descoption = &desc->sname[0];
> + desclen = &desc->snamelen;
> + descpos = &desc->snamepos;
> + }
> +
> + assert(descoption && desclen && descpos);
> +
> + if (*desclen)
> + test_ignore_opts(descoption, descpos, desclen);
> +
> + if (*descpos < *desclen)
> + break;
> +
> + if (*descpos == *desclen)
> + *descpos = -1;
> + }
> +
> + assert(*descpos != -1);
> +
> + optcode = descoption[*descpos];
> + optlen = descoption[*descpos + 1];
> +
> + if (verbose)
> + printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
> + len, optlen);
> +
> + assert(code == optcode);
> + assert(len == optlen);
> +
> + for (i = 0; i < len; i++) {
> +
> + if (verbose)
> + printf("0x%02x(0x%02x) ", option[i],
> + descoption[*descpos + 2 + i]);
> +
> + assert(option[i] == descoption[*descpos + 2 + i]);
> + }
> +
> + if (verbose)
> + printf("\n");
> +
> + *descpos += optlen + 2;
> +
> + test_ignore_opts(descoption, descpos, desclen);
> +
> + if (desc->pos != -1 && desc->pos == desc->len)
> + desc->pos = -1;
> +
> + if (desc->filepos != -1 && desc->filepos == desc->filelen)
> + desc->filepos = -1;
> +
> + if (desc->snamepos != -1 && desc->snamepos == desc->snamelen)
> + desc->snamepos = -1;
> +
> + return 0;
> +}
> +
> +static void test_options(struct option_desc *desc)
> +{
> + uint8_t *options = NULL;
> + uint8_t *file = NULL;
> + uint8_t *sname = NULL;
> + int optlen = 0;
> + int filelen = 0;
> + int snamelen = 0;
> + int buflen = 0;
> + DHCPMessage *message;
_cleanup_free_
> + int res;
> +
> + if (desc) {
> + file = &desc->file[0];
> + filelen = desc->filelen;
> + if (!filelen)
> + desc->filepos = -1;
> +
> + sname = &desc->sname[0];
> + snamelen = desc->snamelen;
> + if (!snamelen)
> + desc->snamepos = -1;
> +
> + options = &desc->options[0];
> + optlen = desc->len;
> + desc->pos = 0;
> + }
> + message = create_message(options, optlen, file, filelen,
> + sname, snamelen);
> +
> + buflen = sizeof(DHCPMessage) + 4 + optlen;
> +
> + if (!desc) {
> + assert((res = __dhcp_option_parse(message, buflen,
> + test_options_cb,
> + NULL)) == -ENOMSG);
> + } else if (desc->success) {
> + assert((res = __dhcp_option_parse(message, buflen,
> + test_options_cb,
> + desc)) >= 0);
> + assert(desc->pos == -1 && desc->filepos == -1 &&
> + desc->snamepos == -1);
> + } else
> + assert((res = __dhcp_option_parse(message, buflen,
> + test_options_cb,
> + desc)) < 0);
> +
> +
> + if (verbose)
> + printf("DHCP type %s\n", dhcp_type(res));
> +
> + free(message);
> +}
> +
> int main(int argc, char *argv[])
> {
> + unsigned int i;
> +
> test_invalid_buffer_length();
> test_cookie();
>
> + test_options(NULL);
> +
> + for (i = 0; i < sizeof(option_tests)/sizeof(struct option_desc); i++)
ELEMENTSOF
> + test_options(&option_tests[i]);
> +
> return 0;
> }
Zbyszek
More information about the systemd-devel
mailing list