[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